Sadržaj

1. Općenito o R-u

2. Rstudio

3. Paketi i Tidyverse

4. Data science proccess

5. Dohvat podataka

6. Priprema podataka

7. Analiza i komunikacija

1. Općenito o R-u

NAPOMENA! Sve što ću danas pričati vrijedi i za druge programske jezike i mislim da se sve ove funkcionalnosti mogu naći i u drugim jezicima, R je samo moj program odabira na kojem sam se učio raditi analitiku, cilj ove prezentacije nije R kao jezik nego stvari koje se mogu općenito raditi u programskim jezicima. U trenutku pisanja R je prema TIOBE indeksu 13. na ljestvici najpopularnijih jezika.

R je besplatan programski jezik koji su u 90-ima osmislili Ross Ihaka i Robert Gentleman iz Novog Zelanda link na wikipedia stranicu. Ono što je važno napomenuti da je R open source jezik i kao takav je besplatan i stalno se razvija jer ima vrlo aktivnu zajednicu.


R se može besplatno skinuti i instalirati ovdje. Instalacija je vrlo jednostavna (next -> next -> next). Kada se instalira, onda se na desktopu stvori ikoan preko koje se pokreće:

Kada se RGui aplikacija pokrene, sučelje izgleda ovako:

2. Rstudio

Većina ljudi kada govori o R-u, zapravo misli na Rstudio sučelje koje se može skinuti i instalirati ovdje. Rstudio koje privatna kompanija koja za sebe kaže sljedeće:

RStudio’s mission is to create free and open-source software for data science, scientific research, and technical communication. We do this to enhance the production and consumption of knowledge by everyone, regardless of economic means, and to facilitate collaboration and reproducible research, both of which are critical to the integrity and efficacy of work in science, education, government, and industry.

Nakon što instaliramo i pokrenemo Rstudio, sučelje izgleda ovako:

Mrkli mrak, zar ne? :)

Što se funkcionalnosti, sve što može Rstudio, može i RGui, no ono u čemu Rstudio prednjači je korisničko iskustvo. Neke od cool funkcionalnosti koje su dostupne u Rstudiju su:

3. Paketi i Tidyverse

Ono što R i slične programe čini izuzetno moćnima je sposobnost podizanja parametrizacije na nekoliko razina apstrakcije.

Najpoznatiji “svemir” aplikacija koje su međusobno konzistentne i međusobno “komuniciraju” je Tidyverse koji razvija upravo Rstudio ekipa:

Popratni materijali vezano za sve pakete u sklopu Tydiversea mogu se pronaći ovdje, pri čemu za ove najvažnije pakete postoje fora šalabahteri. Osim šalabahtera postoje i online knjige, te čak i webinari.

Naravno da ovo nije cijeli “svemir” R paketa, koji trenutno broji preko 15000 paketa.

4. Data science proccess

Proces svake kvantitativne analize se sastoji od 3 ključna dijela i kod sva 3 dijela R nudi vrhunska rješenja.

5. Povezivanje s izvorima podataka

5.1. ECB

ECB ima jako dobro osmišljen sustav skladišta podataka gdje je svaki podatak jednoznačno određen sa jedinstvenim kodom - primjer CLIFS indikatora za HR link:

CLIFS.M.HR._Z.4F.EC.CLIFS_CI.IDX

library(ecb)
library(tidyverse)
library(lubridate)
pom <- get_data("CLIFS.M.._Z.4F.EC.CLIFS_CI.IDX") %>% select(ref_area,obstime,obsvalue) %>% mutate(datum = make_date(ifelse(substr(obstime,6,7)=="12",as.numeric(substr(obstime,1,4))+1,as.numeric(substr(obstime,1,4))), ifelse(substr(obstime,6,7)=="12",1,as.numeric(substr(obstime,6,7))+1), 1)-1) 
ggplot(pom,aes(x=datum,y=obsvalue)) + geom_line() + facet_wrap(~ref_area)

reg = data.frame(ref_area=c("AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB","U2","I8"),country=c("Austria","Belgium","Bulgaria","Croatia","Cyprus","Czech Republic","Denmark","Estonia","Finland","France","Germany","Greece","Hungary","Ireland","Italy","Latvia","Lithuania","Luxembourg","Malta","Netherlands","Poland","Portugal","Romania","Slovak Republic","Slovenia","Spain","Sweden","Great Britain","EA changing comp.","Euro Area 19"),regija=c("Other EU","Other EU","CEE","HR","Other EU","CEE","Other EU","CEE","Other EU","Other EU","Other EU","Other EU","CEE","Other EU","Other EU","CEE","CEE","Other EU","Other EU","Other EU","CEE","Other EU","CEE","CEE","CEE","Other EU","Other EU","Other EU","EA changing comp.","Euro Area 19"))
pom <- pom %>% left_join(reg,by="ref_area") %>% group_by(datum,regija) %>% summarise(clifs=mean(obsvalue,na.rm=T))
Column `ref_area` joining character vector and factor, coercing into character vector
ggplot(pom,aes(x=datum,y=clifs,col=regija)) + geom_line() + theme(legend.title = element_blank(),legend.position = "top") + labs(x="",y="CLIFS indeks")

rm(pom)

5.2. Eurostat

Eurostat isto ima svoj paket za pristup R-a na njihovo skladište podataka. Kod njih je pristup malo drukčije organiziran, tako da najprije treba specificirati tablicu na koju se spajamo - primjer za BDP.

library(eurostat)
# 1.1. YOY stopa rasta BDP-a
pom1 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="B1GQ" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,bdp=values) %>% arrange(time) %>% as.data.frame()
trying URL 'https://ec.europa.eu/eurostat/estat-navtree-portlet-prod/BulkDownloadListing?sort=1&file=data%2Fnamq_10_gdp.tsv.gz'
Content type 'application/octet-stream;charset=UTF-8' length 13884763 bytes (13.2 MB)
downloaded 13.2 MB
# 1.2. Doprinos - potrošnja kućanstava
pom2 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="P31_S14_S15" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,c_hh=values) %>% arrange(time)

# 1.3. Doprinos - potrošnja države
pom3 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="P3_S13" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,c_govt=values) %>% arrange(time)

# 1.4. Doprinos - bruto investicije
pom4 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="P5G" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,i_gross=values) %>% arrange(time)

# 1.5. Doprinos - izvoz robe i usluga
pom5 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="P6" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,ex=values) %>% arrange(time)

# 1.6. Doprinos - uvoz robe i usluga
pom6 <- get_eurostat(id="namq_10_gdp") %>% filter(geo=="HR" & na_item=="P7" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,im=values) %>% arrange(time)

# opcija 1 - uvijek gledamo godišnje BDP-ove
pom <- left_join(pom1,pom2,by="time") %>% left_join(pom3,by="time") %>% left_join(pom4,by="time") %>% left_join(pom5,by="time") %>% left_join(pom6,by="time") %>% mutate(datum = make_date(ifelse(month(time)>=10,year(time)+1,year(time)),ifelse(month(time)>=10,1,month(time)+3),1) - 1, bdp_y = (bdp + lag(bdp,1)+ lag(bdp,2) + lag(bdp,3))*1000000 , c_hh_y = (c_hh + lag(c_hh,1)+ lag(c_hh,2) + lag(c_hh,3))*1000000 , c_govt_y = (c_govt + lag(c_govt,1)+ lag(c_govt,2) + lag(c_govt,3))*1000000 , i_gross_y = (i_gross + lag(i_gross,1)+ lag(i_gross,2) + lag(i_gross,3))*1000000 , ex_y = (ex + lag(ex,1)+ lag(ex,2) + lag(ex,3))*1000000 , im_y = (im + lag(im,1)+ lag(im,2) + lag(im,3))*1000000) %>% mutate(dbdp = (bdp_y/lag(bdp_y,4)-1)*100 , dop_c_hh = (c_hh_y/lag(c_hh_y,4)-1)*100*lag(c_hh_y,4)/lag(bdp_y,4) , dop_c_govt = (c_govt_y/lag(c_govt_y,4)-1)*100*lag(c_govt_y,4)/lag(bdp_y,4) , dop_i_gross = (i_gross_y/lag(i_gross_y,4)-1)*100*lag(i_gross_y,4)/lag(bdp_y,4) , dop_ex = (ex_y/lag(ex_y,4)-1)*100*lag(ex_y,4)/lag(bdp_y,4) , dop_im = -(im_y/lag(im_y,4)-1)*100*lag(im_y,4)/lag(bdp_y,4)) %>% select(datum,dbdp,dop_c_hh,dop_c_govt,dop_i_gross,dop_ex,dop_im) %>% na.omit()
colnames(pom) <- c("datum","BDP","Potrošnja kućanstava","Javna potrošnja","Bruto investicije","Izvoz","Uvoz")
pom <- pom %>% gather(key = "varijabla",value = "iznos",-datum)
ggplot(pom %>% filter(varijabla!="BDP"),aes(x=datum,y=iznos,fill=varijabla)) + geom_col(position="stack") + geom_point(data=pom %>% filter(varijabla=="BDP"),aes(x=datum,y=iznos)) + theme(legend.position = "top", legend.title = element_blank()) + labs(x="",y="")

rm(pom1,pom2,pom3,pom4,pom5,pom6,pom)

5.3. Svjetska Banka

Kod njih pristup podacima funkcionira na sličan način kao i kod ECB-a, gdje svaki indikator ima jedinstveni kod - primjer za indikator trgovine na tržištu kapitala u %BDP-a.

library(wbstats)
reg = data.frame(ctry=c("AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB","U2","I8"),country=c("Austria","Belgium","Bulgaria","Croatia","Cyprus","Czech Republic","Denmark","Estonia","Finland","France","Germany","Greece","Hungary","Ireland","Italy","Latvia","Lithuania","Luxembourg","Malta","Netherlands","Poland","Portugal","Romania","Slovak Republic","Slovenia","Spain","Sweden","Great Britain","EA changing comp.","Euro Area 19"),regija=c("Other EU","Other EU","CEE","HR","Other EU","CEE","Other EU","CEE","Other EU","Other EU","Other EU","Other EU","CEE","Other EU","Other EU","CEE","CEE","Other EU","Other EU","Other EU","CEE","Other EU","CEE","CEE","CEE","Other EU","Other EU","Other EU","EA changing comp.","Euro Area 19"))
stocks_traded <- wb(indicator = "CM.MKT.TRAD.GD.ZS")
pom <- stocks_traded %>% filter(iso2c %in% reg$ctry & date %in% c("2014","2015","2016","2017","2018")) %>% select(date,ctry=iso2c,value) %>% group_by(ctry) %>% summarise(value=mean(value,na.rm=T)) %>% left_join(reg,by="ctry") %>% filter(ctry!="US") %>% mutate(regija=ifelse(regija=="CEE","Zemlje SIE",ifelse(regija=="Other EU","Ostale EU zemlje","HR")))
Column `ctry` joining character vector and factor, coercing into character vector
ggplot(pom,aes(x=reorder(ctry,-value),y=value)) + geom_col(aes(fill=regija)) + labs(x="",y="") + theme(legend.position="top",legend.title = element_blank())

rm(reg,stocks_traded,pom)

5.4. OECD

Jedan fora primjer mogućnosti R-a, su rezultati financijske pismenosti koju provodi OECD i koju objalvjuje u PDF-u. Postoji paket u R-u koji ima spoobnost čitanja PDF-ova i uspio je učitati ove podatke sa slike na stranici 10.

library(tabulizer)
pismenost_tablica <- extract_tables("http://www.oecd.org/daf/fin/financial-education/OECD-INFE-International-Survey-of-Adult-Financial-Literacy-Competencies.pdf")
temp <- pismenost_tablica[[3]]
temp <- as.data.frame(temp)
colnames(temp)<-c("ctry_score","knowledge_score","behaviour_score","attitude_score")
temp <- temp %>% separate(ctry_score,c("country","financial_knowledge")," \\(") %>% mutate(financial_knowledge=str_replace(financial_knowledge,"\\)","")) %>% mutate(financial_knowledge=as.numeric(financial_knowledge),knowledge_score=as.character(knowledge_score),behaviour_score=as.character(behaviour_score),attitude_score=as.character(attitude_score)) %>% mutate(knowledge_score=as.numeric(knowledge_score),behaviour_score=as.numeric(behaviour_score),attitude_score=as.numeric(attitude_score))
financijska_pismenost <- temp
reg = data.frame(ctry=c("AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB","U2","US"),country=c("Austria","Belgium","Bulgaria","Croatia","Cyprus","Czech Republic","Denmark","Estonia","Finland","France","Germany","Greece","Hungary","Ireland","Italy","Latvia","Lithuania","Luxembourg","Malta","Netherlands","Poland","Portugal","Romania","Slovak Republic","Slovenia","Spain","Sweden","United Kingdom","EA changing comp.","United States"),regija=c("Other EU","Other EU","CEE","HR","Other EU","CEE","Other EU","CEE","Other EU","Other EU","Other EU","Other EU","CEE","Other EU","Other EU","CEE","CEE","Other EU","Other EU","Other EU","CEE","Other EU","CEE","CEE","CEE","Other EU","Other EU","Other EU","EA changing comp.","US"))
pom <- financijska_pismenost %>% filter(country %in% reg$country) %>% left_join(reg,by="country")
Column `country` joining character vector and factor, coercing into character vector
ggplot(pom,aes(x=reorder(ctry,-financial_knowledge),y=financial_knowledge)) + geom_col(aes(fill=regija)) + geom_hline(yintercept = financijska_pismenost$financial_knowledge[financijska_pismenost$country=="Average, all countries"]) + labs(x="",y="Financijska pismenost") + theme(legend.position="top")

rm(pismenost_tablica,temp,financijska_pismenost,pom)

5.5. EIOPA podaci

EIOPA nije napredna kao ECB ili EUROSTAT u objavi podataka i objavljuje ih u excelima, no i za to imamo sistem.

6. Priprema podataka

Važno je naglasiti da je za kvalitetnu analizu nužna dobra priprema podataka. Prema istraživanju CrowdFlower-a, u Data science-u se 80% vremena svodi na pripremu podataka, što je ujedno i najmanje zanimljiv dio procesa.

6.1. Tidy struktura podataka

Kako bi se vrijeme potrebno za obradu podataka, ali i vrijeme za analizu podataka smanjilo, nužno je da podaci budu u tidy formatu.

6.2. Financijski računi

Financijske račune dobivamo na krajnje nestrukturiran način i koji se nalaze ovdje. Ono što R omogućuje je sklapanje u 1 bazu koja se onda može koristiti za analizu i ne samo to nego je na taj način 970MB podataka u excelima pretvoreno u 2.7MB veliki dataframe.

Ovakva struktura podataka omogućuje sljedeće slike:

library(igraph)

Attaching package: 㤼㸱igraph㤼㸲

The following objects are masked from 㤼㸱package:lubridate㤼㸲:

    %--%, union

The following objects are masked from 㤼㸱package:dplyr㤼㸲:

    as_data_frame, groups, union

The following objects are masked from 㤼㸱package:purrr㤼㸲:

    compose, simplify

The following object is masked from 㤼㸱package:tidyr㤼㸲:

    crossing

The following object is masked from 㤼㸱package:tibble㤼㸲:

    as_data_frame

The following objects are masked from 㤼㸱package:stats㤼㸲:

    decompose, spectrum

The following object is masked from 㤼㸱package:base㤼㸲:

    union
# Slika 11. Mreža transakcija ####
load("FinRacuni.Rda")
t0 <- as.Date("2012-03-31")
t1 <- as.Date("2019-06-30")
br_dana <- as.numeric(t1-t0)
# anualizirani rast sektora na temelju transakcija između t0 i t1
# početna stanja
pom11 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb)) %>% group_by(datum,sektor_mb) %>% filter(vrsta_iznosa=="BAL T" & vrsta_imovine=="Total" & razina=="Assets" & !sektor %in% c("TOTAL","NA") & !protustrana %in% c("TOTAL","NA") & datum==t0) %>% summarise(stanja=sum(iznos,na.rm = T))
# ukupne transakcije po sektorima (za izračun rasta na temelju transakcija)
pom12 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb)) %>% group_by(sektor_mb) %>% filter(vrsta_iznosa=="TRANS T" & vrsta_imovine=="Total" & razina=="Assets" & !sektor %in% c("TOTAL","NA") & !protustrana %in% c("TOTAL","NA") & datum>t0) %>% summarise(cum_trans=sum(iznos,na.rm = T))
# izračun rasta na temelju transakcija
pom1 <- left_join(pom11,pom12,by="sektor_mb") %>% mutate(cum_rast=((cum_trans)/stanja)*100) %>% mutate(an_rast=((1+cum_rast/100)^(365/br_dana)-1)*100)
# doprinosi protustranki anualiziranom rastu sektora na temelju transakcija između t0 i t1
# kumulativne transakcije po protustranci
pom2 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb) , protustrana_mb = ifelse(protustrana_mb=="Ostali financijski posrednici","Ostale FI",protustrana_mb)) %>% group_by(sektor_mb,protustrana_mb) %>% filter(vrsta_iznosa=="TRANS T" & vrsta_imovine=="Total" & razina=="Assets" & !sektor %in% c("TOTAL","NA") & !protustrana %in% c("TOTAL","NA") & datum>t0) %>% summarise(cum_trans_sekt=sum(iznos,na.rm = T))
# sklapanje i računanje stopa rasta
pom <- left_join(pom2,pom1,by=c("sektor_mb")) %>% mutate(cum_dop_sekt = (cum_trans_sekt/stanja)*100) %>% mutate(doprinos_trans=((1+cum_dop_sekt/100)^(365/br_dana)-1)*100)

# definiranje bridova
bridovi <- pom %>% as.data.frame() %>% mutate(sektor_mb=ifelse(sektor_mb=="Poduzeća","POD",ifelse(sektor_mb=="Ostale FI","OFI",ifelse(sektor_mb=="Centralna banka","CB",ifelse(sektor_mb=="Kreditne institucije","KI",ifelse(sektor_mb=="Investicijski fondovi","IF",ifelse(sektor_mb=="Osiguranja","OS",ifelse(sektor_mb=="Mirovinski fondovi","MF",ifelse(sektor_mb=="Država","DRŽ",ifelse(sektor_mb=="Stanovništvo","KUĆ",ifelse(sektor_mb=="Inozemstvo","INO",ifelse(sektor_mb=="Ostali financijski posrednici","OFP","NA")))))))))))) %>% mutate(protustrana_mb=ifelse(protustrana_mb=="Poduzeća","POD",ifelse(protustrana_mb=="Ostale FI","OFI",ifelse(protustrana_mb=="Centralna banka","CB",ifelse(protustrana_mb=="Kreditne institucije","KI",ifelse(protustrana_mb=="Investicijski fondovi","IF",ifelse(protustrana_mb=="Osiguranja","OS",ifelse(protustrana_mb=="Mirovinski fondovi","MF",ifelse(protustrana_mb=="Država","DRŽ",ifelse(protustrana_mb=="Stanovništvo","KUĆ",ifelse(protustrana_mb=="Inozemstvo","INO",ifelse(protustrana_mb=="Ostali financijski posrednici","OFP","NA"))))))))))))

# definiranje vrhova 
vrhovi <- pom1 %>% ungroup() %>% mutate(sektor_mb=ifelse(sektor_mb=="Poduzeća","POD",ifelse(sektor_mb=="Ostale FI","OFI",ifelse(sektor_mb=="Centralna banka","CB",ifelse(sektor_mb=="Kreditne institucije","KI",ifelse(sektor_mb=="Investicijski fondovi","IF",ifelse(sektor_mb=="Osiguranja","OS",ifelse(sektor_mb=="Mirovinski fondovi","MF",ifelse(sektor_mb=="Država","DRŽ",ifelse(sektor_mb=="Stanovništvo","KUĆ",ifelse(sektor_mb=="Inozemstvo","INO",ifelse(sektor_mb=="Ostali financijski posrednici","OFP","NA")))))))))))) %>% mutate(hanfa=ifelse(sektor_mb %in% c("IF","MF","OS","OFI","OFP"),"da","ne")) %>% filter(sektor_mb!="CB") %>% select(sektor_mb,rast_trans=an_rast,hanfa)

# uzimanje samo bridova koji su različito od 0% i samo onih bridova koji imaju veze sa HANFA-inim sektorima
bridovi <- bridovi %>% filter((doprinos_trans<=-0.5 | doprinos_trans>=0.5) & (sektor_mb %in% c("MF","OS","IF","OFI","OFP") | protustrana_mb %in% c("MF","OS","IF","OFI","OFP"))) %>% filter(sektor_mb!=protustrana_mb)

# kreiranje mrežnog objekta
graf <- graph_from_data_frame(d = bridovi, vertices = vrhovi, directed = T)
# postavljanje boje vrha (ako rastao zeleno, ako pao onda crveno)
V(graf)$color <- ifelse(V(graf)$rast_trans <=(-10), "firebrick4", ifelse(V(graf)$rast_trans <=(-5),"orangered",ifelse(V(graf)$rast_trans<=0,"lightsalmon",ifelse(V(graf)$rast_trans <=5,"gold",ifelse(V(graf)$rast_trans <=10,"yellowgreen","seagreen4")))))
# postavljanje boje brida (ako rasla zeleno, ako pala crveno)
E(graf)$color <- ifelse(E(graf)$doprinos_trans <=(-5), "firebrick4", ifelse(E(graf)$doprinos_trans <=(-2.5),"orangered",ifelse(E(graf)$doprinos_trans <=0,"lightsalmon",ifelse(E(graf)$doprinos_trans <=2.5,"gold",ifelse(E(graf)$doprinos_trans <=5,"yellowgreen","seagreen4")))))
# slika mreže povezanosti - jednake veličine vrhova
plot(graf, vertex.size = 25, edge.arrow.size = 0.5, layout=layout_nicely(graf), vertex.label.color = "black", vertex.frame.color=NA,vertex.shape=ifelse(V(graf)$hanfa=="da","square","circle"))
# Add a legend
legend("topleft", legend=c("<-oo;-10] ; <-10;-5]", "<-10;-5] ; <-5;-2,5]","<-5;0] ; <-2,5;-0,5]","<0;5] ; [0,5;2,5]","<5;10] ; <2,5;5]","<10;+oo> ; <5;+oo>"), fill=c("firebrick4", "orangered","lightsalmon","gold","yellowgreen","seagreen4"), title = "Vrhovi (rast na temelju transakcija) ; \n Strelice (doprinosi rastu)", cex=0.8, bty="n")

# brisanje privremenih tablica
rm(t0,t1,br_dana,pom1,pom2,pom11,pom12,pom,bridovi,vrhovi,graf)

# Slika 12. Mreža stanja ####
zadnji_datum <- "2019-06-30"
# veličina direktne povezanosti u apsolutnoj vrijednosti
pom1 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb) , protustrana_mb = ifelse(protustrana_mb=="Ostali financijski posrednici","Ostale FI",protustrana_mb)) %>% filter(datum==zadnji_datum & vrsta_iznosa=="BAL T" & vrsta_imovine=="Total" & razina=="Assets" & !sektor %in% c("TOTAL","NA") & !protustrana %in% c("TOTAL","NA")) %>% group_by(sektor_mb,protustrana_mb) %>% summarise(iznos=sum(iznos,na.rm = T)/1000000000)
# ukupna veličina sektora (ona će nam služiti da relativiziramo povezanost i obojimo u 4 boje)
pom2 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb)) %>% filter(datum==zadnji_datum & vrsta_iznosa=="BAL T" & vrsta_imovine=="Total" & razina=="Assets" & !sektor %in% c("TOTAL","NA") & protustrana %in% c("TOTAL")) %>% group_by(sektor_mb) %>% summarise(velicina_sektor=sum(iznos,na.rm = T)/1000000000)
# ukupna veličina protustrane (ona će nam služiti da relativiziramo povezanost i kreiramo debljinu linije)
pom3 <- financijski_racuni %>% mutate(protustrana_mb = ifelse(protustrana_mb=="Ostali financijski posrednici","Ostale FI",protustrana_mb)) %>% filter(datum==zadnji_datum & vrsta_iznosa=="BAL T" & vrsta_imovine=="Total" & razina=="Assets" & !protustrana %in% c("TOTAL","NA") & sektor %in% c("TOTAL")) %>% group_by(protustrana_mb) %>% summarise(velicina_protustrana=sum(iznos,na.rm = T)/1000000000)
# ukupna veličina izloženosti sektoru financijskih usluga (ona će nam služiti da relativiziramo povezanost i kreiramo veličinu kugle za neHANFA-ine vrhove)
pom4 <- financijski_racuni %>% mutate(sektor_mb = ifelse(sektor_mb=="Ostali financijski posrednici","Ostale FI",sektor_mb)) %>% filter(datum==zadnji_datum & vrsta_iznosa=="BAL T" & vrsta_imovine=="Total" & razina=="Liabilities" & !sektor %in% c("TOTAL","NA") & protustrana_mb %in% c("Mirovinski fondovi","Osiguranja","Investicijski fondovi","Ostali financijski posrednici","Ostale FI")) %>% group_by(sektor_mb) %>% summarise(izlozenost_hanfa=sum(iznos,na.rm = T)/1000000000)
# sklapanje u 1 tibble
bridovi <- left_join(pom1,pom2,by="sektor_mb") %>% left_join(pom3,by="protustrana_mb") %>% left_join(pom4,by="sektor_mb") %>% mutate(izlozenost_velicina_sektor=iznos/velicina_sektor*100 , izlozenost_velicina_protustrana=iznos/velicina_protustrana*100) %>% as.data.frame() %>% mutate(sektor_mb=ifelse(sektor_mb=="Poduzeća","POD",ifelse(sektor_mb=="Ostale FI","OFI",ifelse(sektor_mb=="Centralna banka","CB",ifelse(sektor_mb=="Kreditne institucije","KI",ifelse(sektor_mb=="Investicijski fondovi","IF",ifelse(sektor_mb=="Osiguranja","OS",ifelse(sektor_mb=="Mirovinski fondovi","MF",ifelse(sektor_mb=="Država","DRŽ",ifelse(sektor_mb=="Stanovništvo","KUĆ",ifelse(sektor_mb=="Inozemstvo","INO",ifelse(sektor_mb=="Ostali financijski posrednici","OFP","NA")))))))))))) %>% mutate(protustrana_mb=ifelse(protustrana_mb=="Poduzeća","POD",ifelse(protustrana_mb=="Ostale FI","OFI",ifelse(protustrana_mb=="Centralna banka","CB",ifelse(protustrana_mb=="Kreditne institucije","KI",ifelse(protustrana_mb=="Investicijski fondovi","IF",ifelse(protustrana_mb=="Osiguranja","OS",ifelse(protustrana_mb=="Mirovinski fondovi","MF",ifelse(protustrana_mb=="Država","DRŽ",ifelse(protustrana_mb=="Stanovništvo","KUĆ",ifelse(protustrana_mb=="Inozemstvo","INO",ifelse(protustrana_mb=="Ostali financijski posrednici","OFP","NA"))))))))))))

# uzimanje samo bridova koji su veći od 5% i samo onih bridova koji imaju veze sa HANFA-inim sektorima
bridovi <- bridovi %>% filter(izlozenost_velicina_sektor>5 & (sektor_mb %in% c("MF","OS","IF","OFI","OFP") | protustrana_mb %in% c("MF","OS","IF","OFI","OFP")))
# definiranje vrhova 
vrhovi <- left_join(pom2,pom4,by="sektor_mb") %>% mutate(sektor_mb=ifelse(sektor_mb=="Poduzeća","POD",ifelse(sektor_mb=="Ostale FI","OFI",ifelse(sektor_mb=="Centralna banka","CB",ifelse(sektor_mb=="Kreditne institucije","KI",ifelse(sektor_mb=="Investicijski fondovi","IF",ifelse(sektor_mb=="Osiguranja","OS",ifelse(sektor_mb=="Mirovinski fondovi","MF",ifelse(sektor_mb=="Država","DRŽ",ifelse(sektor_mb=="Stanovništvo","KUĆ",ifelse(sektor_mb=="Inozemstvo","INO",ifelse(sektor_mb=="Ostali financijski posrednici","OFP","NA")))))))))))) %>% mutate(hanfa=ifelse(sektor_mb %in% c("IF","MF","OS","OFI","OFP"),"da","ne")) %>% mutate(velicina_kruga=ifelse(hanfa=="da",velicina_sektor,izlozenost_hanfa)) %>% filter(sektor_mb!="CB")

# kreiranje mrežnog objekta
graf <- graph_from_data_frame(d = bridovi, vertices = vrhovi, directed = T)
# postavljanje boje vrha (ako Hanfa nadzire "blue", inače "gray")
V(graf)$color <- ifelse(V(graf)$hanfa == "da", "deepskyblue3", "azure3")
# veličina oznaka na vrhovima
V(graf)$label.cex = 0.8
# postavljanje boje brida (ako <5% imovine, onda nema brida, ako do 10% onda zeleno, ako do 20% onda narančasto, a preko crveno)
E(graf)$color <- ifelse(E(graf)$izlozenost_velicina_sektor <= 10, "darkgreen", ifelse(E(graf)$izlozenost_velicina_sektor <= 15,"yellow3",ifelse(E(graf)$izlozenost_velicina_sektor<=20,"darkorange","darkred")))

# slika mreže povezanosti

# razne debljine bridova
#plot(graf, vertex.size = V(graf)$velicina_kruga/2, edge.arrow.size = 0.5, layout=layout_nicely(graf), edge.width = E(graf)$izlozenost_velicina_sektor/8, vertex.label.color = "black", vertex.frame.color=NA)
# jednake debljine bridova
plot(graf, vertex.size = 25, edge.arrow.size = 0.5, layout=layout_nicely(graf), edge.width = 2, vertex.label.color = "black", vertex.frame.color=NA)
# legenda
legend("topleft", legend=c("<5","<5;10]","<10;15]","<15;20]",">20"), fill=c("white", "darkgreen","yellow3","darkorange","darkred"), title = "Oznake boja strelica \n (u % ukupne imovine sektora)", cex=0.8, bty="n")

# brisanje privremenih tablica
rm(zadnji_datum,br_dana,pom1,pom2,pom3,pom4,pom,bridovi,vrhovi,graf)
object 'br_dana' not foundobject 'pom' not found

6.3. Shiny aplikacija

Kada su podaci u tidy formatu, onda je moguće napraviti sljedeću aplikaciju za analizu kretanja u sustavu.

7. Analiza i komunikacija rezultata

7.1. Plotly

Ovo je primjer Gantt-grafikona koji ste vidjeli prošli tjedan sa vremenskim planom aktivnosti oko pripreme 4. broja Makroprudencijalnog skenera rizika.

7.2. Gapminder primjer

Hans Rosling je jedno od najpoznatijih imena u statističkim krugovima i veliki popularizator “data sciencea”, njegov TED talk je jedan od najgledanijih ikada (velika preporuka da ga pogledate).

7.3. Shiny mreže OeNB-a

Vidi folder JVI_Contagion.

7.4. Mapa EU

Vrlo jednostavno se može napraviti i mapa EU po zemljama. Npr, prikaz definicije regija koje prikazujemo u skeneru.

library(tidyverse)
library(grid)
library(rworldmap)
library(eurostat)
library(lubridate)

# Get the world map
worldMap <- getMap()

# Member States of the European Union
reg = data.frame(ref_area=c("AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB"),country=c("Austria","Belgium","Bulgaria","Croatia","Cyprus","Czech Rep.","Denmark","Estonia","Finland","France","Germany","Greece","Hungary","Ireland","Italy","Latvia","Lithuania","Luxembourg","Malta","Netherlands","Poland","Portugal","Romania","Slovakia","Slovenia","Spain","Sweden","United Kingdom"),regija=c("Other EU","Other EU","CEE","HR","Other EU","CEE","Other EU","CEE","Other EU","Other EU","Other EU","Other EU","CEE","Other EU","Other EU","CEE","CEE","Other EU","Other EU","Other EU","CEE","Other EU","CEE","CEE","CEE","Other EU","Other EU","Other EU"))

# Select only the index of states member of the E.U.
indEU <- which(worldMap$NAME %in% reg$country)

# Extract longitude and latitude border's coordinates of members states of E.U. 
europeCoords <- lapply(indEU, function(i){
  df <- data.frame(worldMap@polygons[[i]]@Polygons[[1]]@coords)
  df$region =as.character(worldMap$NAME[i])
  colnames(df) <- list("long", "lat", "region")
  return(df)
})

europeCoords <- do.call("rbind", europeCoords)

# 1. Mapa regija ####
europeanUnionTable <- data.frame(country = reg$country, value = reg$regija)
europeCoords$value <- europeanUnionTable$value[match(europeCoords$region,europeanUnionTable$country)]

# Plot the map
P <- ggplot() + geom_polygon(data = europeCoords, aes(x = long, y = lat, group = region, fill = value), colour = "black", size = 0.1) + coord_map(xlim = c(-13, 35),  ylim = c(32, 71))
P <- P + scale_fill_discrete(name = "Regija", na.value = "grey50")
P <- P + theme(#panel.grid.minor = element_line(colour = NA), panel.grid.minor = element_line(colour = NA),
  #panel.background = element_rect(fill = NA, colour = NA),
  axis.text.x = element_blank(),
  axis.text.y = element_blank(), axis.ticks.x = element_blank(),
  axis.ticks.y = element_blank(), axis.title = element_blank(),
  #rect = element_blank(),
  plot.margin = unit(0 * c(-1.5, -1.5, -1.5, -1.5), "lines"))
P


P <- P + scale_fill_gradient(name = "Growth Rate", low = "#FF0000FF", high = "#FFFF00FF", na.value = "grey50")
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

Jednako jednostavno se može napraviti i kontinuirana mapa koja npr. prikazuje kumulativni rast BDP-a od 2010. po EU zemljama.

pom <- get_eurostat(id="namq_10_gdp") %>% filter(na_item=="B1GQ" & s_adj=="NSA" & unit=="CLV10_MNAC") %>% select(time,geo,bdp=values) %>% arrange(time) %>% as.data.frame() %>% group_by(geo) %>% mutate(bdp_y = (bdp + lag(bdp,1)+ lag(bdp,2) + lag(bdp,3))) %>% filter(time>="2007-10-01") %>% mutate(datum = make_date(ifelse(month(time)>=10,year(time)+1,year(time)),ifelse(month(time)>=10,1,month(time)+3),1) - 1) %>% select(datum,ref_area=geo,bdp_y) %>% na.omit() %>% ungroup()
Reading cache file C:\Users\MBAMBU~1\AppData\Local\Temp\Rtmp8kR8F4/eurostat/namq_10_gdp_date_code_TF.rds
Table  namq_10_gdp  read from cache file:  C:\Users\MBAMBU~1\AppData\Local\Temp\Rtmp8kR8F4/eurostat/namq_10_gdp_date_code_TF.rds
baza <- pom %>% filter(datum=="2010-12-31") %>% select(ref_area,baza=bdp_y)
delta_bdp <- left_join(pom,baza,by=c("ref_area")) %>% mutate(indeks=bdp_y/baza*100) %>% filter(datum=="2019-09-30") %>% left_join(reg,by="ref_area") %>% na.omit()
Column `ref_area` joining factors with different levels, coercing to character vector
europeanUnionTable <- data.frame(country = delta_bdp$country, value = delta_bdp$indeks)
europeCoords$value <- europeanUnionTable$value[match(europeCoords$region,europeanUnionTable$country)]

# Plot the map
P <- ggplot() + geom_polygon(data = europeCoords, aes(x = long, y = lat, group = region, fill = value), colour = "black", size = 0.1) + coord_map(xlim = c(-13, 35),  ylim = c(32, 71))
P <- P + scale_fill_gradient(name = "Kumulativni rast BDP-a od 2010.", low = "red", high = "green", na.value = "grey50")
P <- P + theme(#panel.grid.minor = element_line(colour = NA), panel.grid.minor = element_line(colour = NA),
  #panel.background = element_rect(fill = NA, colour = NA),
  axis.text.x = element_blank(),
  axis.text.y = element_blank(), axis.ticks.x = element_blank(),
  axis.ticks.y = element_blank(), axis.title = element_blank(),
  #rect = element_blank(),
  plot.margin = unit(0 * c(-1.5, -1.5, -1.5, -1.5), "lines"))
P

# brisanje privremenih tablica
rm(worldMap,reg,indEU,europeCoords,europeanUnionTable,P,pom,baza,delta_bdp)

7.5. Word cloud riječi koje su se najčešće koristile u 3. broju skenera

LS0tDQp0aXRsZTogIlV2b2QgdSBSIg0KYXV0aG9yOiAiTWFyaW8gQmFtYnVsb3ZpxIciDQpkYXRlOiAiMTIuMi4yMDIwLiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIFNhZHLFvmFqDQoNCiMjIyMgMS4gT3DEh2VuaXRvIG8gUi11DQojIyMjIDIuIFJzdHVkaW8NCiMjIyMgMy4gUGFrZXRpIGkgVGlkeXZlcnNlDQojIyMjIDQuIERhdGEgc2NpZW5jZSBwcm9jY2Vzcw0KIyMjIyA1LiBEb2h2YXQgcG9kYXRha2ENCiMjIyMgNi4gUHJpcHJlbWEgcG9kYXRha2ENCiMjIyMgNy4gQW5hbGl6YSBpIGtvbXVuaWthY2lqYQ0KDQojIyAxLiBPcMSHZW5pdG8gbyBSLXUNCg0KKipOQVBPTUVOQSEgU3ZlIMWhdG8gxId1IGRhbmFzIHByacSNYXRpIHZyaWplZGkgaSB6YSBkcnVnZSBwcm9ncmFtc2tlIGplemlrZSBpIG1pc2xpbSBkYSBzZSBzdmUgb3ZlIGZ1bmtjaW9uYWxub3N0aSBtb2d1IG5hxIdpIGkgdSBkcnVnaW0gamV6aWNpbWEsIFIgamUgc2FtbyBtb2ogcHJvZ3JhbSBvZGFiaXJhIG5hIGtvamVtIHNhbSBzZSB1xI1pbyByYWRpdGkgYW5hbGl0aWt1LCBjaWxqICBvdmUgcHJlemVudGFjaWplIG5pamUgUiBrYW8gamV6aWsgbmVnbyBzdHZhcmkga29qZSBzZSBtb2d1IG9wxIdlbml0byByYWRpdGkgdSBwcm9ncmFtc2tpbSBqZXppY2ltYS4gVSB0cmVudXRrdSBwaXNhbmphIFIgamUgcHJlbWEgW1RJT0JFIGluZGVrc3VdKGh0dHBzOi8vd3d3LnRpb2JlLmNvbS90aW9iZS1pbmRleC8pIDEzLiBuYSBsamVzdHZpY2kgbmFqcG9wdWxhcm5pamloIGplemlrYS4qKg0KDQpSIGplIGJlc3BsYXRhbiBwcm9ncmFtc2tpIGplemlrIGtvamkgc3UgdSA5MC1pbWEgb3NtaXNsaWxpIFJvc3MgSWhha2EgaSBSb2JlcnQgR2VudGxlbWFuIGl6IE5vdm9nIFplbGFuZGEgW2xpbmsgbmEgd2lraXBlZGlhIHN0cmFuaWN1XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SXyhwcm9ncmFtbWluZ19sYW5ndWFnZSkpLiBPbm8gxaF0byBqZSB2YcW+bm8gbmFwb21lbnV0aSBkYSBqZSBSICoqb3BlbiBzb3VyY2UgamV6aWsqKiBpIGthbyB0YWthdiBqZSAqKmJlc3BsYXRhbioqIGkgc3RhbG5vIHNlIHJhenZpamEgamVyIGltYSB2cmxvIGFrdGl2bnUgemFqZWRuaWN1Lg0KDQogIVtdKG9zbml2YcSNaS5QTkcpIA0KDQoqKioNCg0KUiBzZSBtb8W+ZSBiZXNwbGF0bm8gc2tpbnV0aSBpIGluc3RhbGlyYXRpIFtvdmRqZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvYmluL3dpbmRvd3MvYmFzZS8pLiBJbnN0YWxhY2lqYSBqZSB2cmxvIGplZG5vc3Rhdm5hIChuZXh0IC0+IG5leHQgLT4gbmV4dCkuIEthZGEgc2UgaW5zdGFsaXJhLCBvbmRhIHNlIG5hIGRlc2t0b3B1IHN0dm9yaSBpa29hbiBwcmVrbyBrb2plIHNlIHBva3JlxIdlOg0KDQohW10oUmd1aV9pa29uYS5QTkcpDQoNCkthZGEgc2UgUkd1aSBhcGxpa2FjaWphIHBva3JlbmUsIHN1xI1lbGplIGl6Z2xlZGEgb3Zha286DQoNCiFbXShSZ3VpLlBORykNCg0KDQojIyAyLiBSc3R1ZGlvDQoNClZlxIdpbmEgbGp1ZGkga2FkYSBnb3ZvcmkgbyBSLXUsIHphcHJhdm8gbWlzbGkgbmEgUnN0dWRpbyBzdcSNZWxqZSBrb2plIHNlIG1vxb5lIHNraW51dGkgaSBpbnN0YWxpcmF0aSBbb3ZkamVdKGh0dHBzOi8vcnN0dWRpby5jb20vKS4gUnN0dWRpbyBrb2plIHByaXZhdG5hIGtvbXBhbmlqYSBrb2phIHphIHNlYmUga2HFvmUgc2xqZWRlxIdlOiANCg0KPiBSU3R1ZGlvJ3MgbWlzc2lvbiBpcyB0byBjcmVhdGUgZnJlZSBhbmQgb3Blbi1zb3VyY2Ugc29mdHdhcmUgZm9yIGRhdGEgc2NpZW5jZSwgc2NpZW50aWZpYyByZXNlYXJjaCwgYW5kIHRlY2huaWNhbCBjb21tdW5pY2F0aW9uLiBXZSBkbyB0aGlzIHRvIGVuaGFuY2UgdGhlIHByb2R1Y3Rpb24gYW5kIGNvbnN1bXB0aW9uIG9mIGtub3dsZWRnZSBieSBldmVyeW9uZSwgcmVnYXJkbGVzcyBvZiBlY29ub21pYyBtZWFucywgYW5kIHRvIGZhY2lsaXRhdGUgY29sbGFib3JhdGlvbiBhbmQgcmVwcm9kdWNpYmxlIHJlc2VhcmNoLCBib3RoIG9mIHdoaWNoIGFyZSBjcml0aWNhbCB0byB0aGUgaW50ZWdyaXR5IGFuZCBlZmZpY2FjeSBvZiB3b3JrIGluIHNjaWVuY2UsIGVkdWNhdGlvbiwgZ292ZXJubWVudCwgYW5kIGluZHVzdHJ5Lg0KDQpOYWtvbiDFoXRvIGluc3RhbGlyYW1vIGkgcG9rcmVuZW1vIFJzdHVkaW8sIHN1xI1lbGplIGl6Z2xlZGEgb3Zha286DQoNCiFbXShSc3R1ZGlvLlBORykNCg0KKipNcmtsaSBtcmFrLCB6YXIgbmU/IDopKioNCg0KxaB0byBzZSBmdW5rY2lvbmFsbm9zdGksIHN2ZSDFoXRvIG1vxb5lIFJzdHVkaW8sIG1vxb5lIGkgUkd1aSwgbm8gb25vIHUgxI1lbXUgUnN0dWRpbyBwcmVkbmphxI1pIGplIGtvcmlzbmnEjWtvIGlza3VzdHZvLiBOZWtlIG9kIGNvb2wgZnVua2Npb25hbG5vc3RpIGtvamUgc3UgZG9zdHVwbmUgdSBSc3R1ZGlqdSBzdToNCg0KKiB0YW1uYSBwb3phZGluYSA6KQ0KKiBwb3Zleml2YW5qZSBzIEdpdGh1Yi1vbSAobyB0b21lIHZpxaFlIGthc25pamUpDQoqIFZpZXdlcg0KKiBSbWFya2Rvd24NCiogU2hpbnkNCiogcG9tb8SHIHByaSBwaXNhbmp1IChyYXpsacSNaXRlIGJvamUgemEgcmF6bGnEjWl0ZSBvYmpla3RlLCB6YXR2YXJhbmplIHphZ3JhZGEsIGF1dG9jb3JyZWN0LCBzdWdlcmlyYW5qZSByaWplxI1pLCBpdGQuLi4pDQoNCiMjIDMuIFBha2V0aSBpIFRpZHl2ZXJzZQ0KDQpPbm8gxaF0byBSIGkgc2xpxI1uZSBwcm9ncmFtZSDEjWluaSBpenV6ZXRubyBtb8SHbmltYSBqZSBzcG9zb2Jub3N0IHBvZGl6YW5qYSBwYXJhbWV0cml6YWNpamUgbmEgbmVrb2xpa28gcmF6aW5hIGFwc3RyYWtjaWplLg0KDQohW10oUGFyYW1ldHJpemFjaWphLlBORykNCg0KTmFqcG96bmF0aWppICJzdmVtaXIiIGFwbGlrYWNpamEga29qZSBzdSBtZcSRdXNvYm5vIGtvbnppc3RlbnRuZSBpIG1lxJF1c29ibm8gImtvbXVuaWNpcmFqdSIgamUgKipUaWR5dmVyc2UqKiBrb2ppIHJhenZpamEgdXByYXZvIFJzdHVkaW8gZWtpcGE6DQoNCiFbXShUaWR5dmVyc2UuUE5HKQ0KDQpQb3ByYXRuaSBtYXRlcmlqYWxpIHZlemFubyB6YSBzdmUgcGFrZXRlIHUgc2tsb3B1IFR5ZGl2ZXJzZWEgbW9ndSBzZSBwcm9uYcSHaSBbb3ZkamVdKGh0dHBzOi8vcnN0dWRpby5jb20vcHJvZHVjdHMvcnBhY2thZ2VzLyksIHByaSDEjWVtdSB6YSBvdmUgbmFqdmHFvm5pamUgcGFrZXRlIHBvc3RvamUgZm9yYSBbxaFhbGFiYWh0ZXJpXShodHRwczovL3JzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pLiBPc2ltIMWhYWxhYmFodGVyYSBwb3N0b2plIGkgW29ubGluZSBrbmppZ2VdKGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2Jvb2tzLyksIHRlIMSNYWsgaSBbd2ViaW5hcmldKGh0dHBzOi8vcmVzb3VyY2VzLnJzdHVkaW8uY29tLykuDQoNCk5hcmF2bm8gZGEgb3ZvIG5pamUgY2lqZWxpICJzdmVtaXIiIFIgcGFrZXRhLCBrb2ppIHRyZW51dG5vIGJyb2ppIHByZWtvIFsxNTAwMCBwYWtldGFdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9jaGVja3MvY2hlY2tfc3VtbWFyeS5odG1sKS4gDQoNCiMjIDQuIERhdGEgc2NpZW5jZSBwcm9jY2Vzcw0KDQpQcm9jZXMgc3Zha2Uga3ZhbnRpdGF0aXZuZSBhbmFsaXplIHNlIHNhc3Rvamkgb2QgMyBrbGp1xI1uYSBkaWplbGEgaSBrb2Qgc3ZhIDMgZGlqZWxhIFIgbnVkaSB2cmh1bnNrYSByamXFoWVuamEuDQoNCiFbXShkYXRhX3NjaWVuY2VfcHJvY2Vzcy5QTkcpDQoNCiMjIDUuIFBvdmV6aXZhbmplIHMgaXp2b3JpbWEgcG9kYXRha2ENCg0KIyMjIDUuMS4gRUNCDQoNCkVDQiBpbWEgamFrbyBkb2JybyBvc21pxaFsamVuIHN1c3RhdiBbc2tsYWRpxaF0YSBwb2RhdGFrYV0oaHR0cDovL3Nkdy5lY2IuZXVyb3BhLmV1L2Jyb3dzZS5kbz9ub2RlPTk2ODk3MjcpIGdkamUgamUgc3Zha2kgcG9kYXRhayBqZWRub3puYcSNbm8gb2RyZcSRZW4gc2EgamVkaW5zdHZlbmltIGtvZG9tIC0gcHJpbWplciBDTElGUyBpbmRpa2F0b3JhIHphIEhSIFtsaW5rXShodHRwOi8vc2R3LmVjYi5ldXJvcGEuZXUvYnJvd3NlU2VsZWN0aW9uLmRvP25vZGU9OTY5MzM0Nyk6DQoNCj4gQ0xJRlMuTS5IUi5fWi40Ri5FQy5DTElGU19DSS5JRFgNCg0KYGBge3IgfQ0KbGlicmFyeShlY2IpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KcG9tIDwtIGdldF9kYXRhKCJDTElGUy5NLi5fWi40Ri5FQy5DTElGU19DSS5JRFgiKSAlPiUgc2VsZWN0KHJlZl9hcmVhLG9ic3RpbWUsb2JzdmFsdWUpICU+JSBtdXRhdGUoZGF0dW0gPSBtYWtlX2RhdGUoaWZlbHNlKHN1YnN0cihvYnN0aW1lLDYsNyk9PSIxMiIsYXMubnVtZXJpYyhzdWJzdHIob2JzdGltZSwxLDQpKSsxLGFzLm51bWVyaWMoc3Vic3RyKG9ic3RpbWUsMSw0KSkpLCBpZmVsc2Uoc3Vic3RyKG9ic3RpbWUsNiw3KT09IjEyIiwxLGFzLm51bWVyaWMoc3Vic3RyKG9ic3RpbWUsNiw3KSkrMSksIDEpLTEpIA0KZ2dwbG90KHBvbSxhZXMoeD1kYXR1bSx5PW9ic3ZhbHVlKSkgKyBnZW9tX2xpbmUoKSArIGZhY2V0X3dyYXAofnJlZl9hcmVhKQ0KDQpgYGANCg0KYGBge3J9DQpyZWcgPSBkYXRhLmZyYW1lKHJlZl9hcmVhPWMoIkFUIiwiQkUiLCJCRyIsIkhSIiwiQ1kiLCJDWiIsIkRLIiwiRUUiLCJGSSIsIkZSIiwiREUiLCJHUiIsIkhVIiwiSUUiLCJJVCIsIkxWIiwiTFQiLCJMVSIsIk1UIiwiTkwiLCJQTCIsIlBUIiwiUk8iLCJTSyIsIlNJIiwiRVMiLCJTRSIsIkdCIiwiVTIiLCJJOCIpLGNvdW50cnk9YygiQXVzdHJpYSIsIkJlbGdpdW0iLCJCdWxnYXJpYSIsIkNyb2F0aWEiLCJDeXBydXMiLCJDemVjaCBSZXB1YmxpYyIsIkRlbm1hcmsiLCJFc3RvbmlhIiwiRmlubGFuZCIsIkZyYW5jZSIsIkdlcm1hbnkiLCJHcmVlY2UiLCJIdW5nYXJ5IiwiSXJlbGFuZCIsIkl0YWx5IiwiTGF0dmlhIiwiTGl0aHVhbmlhIiwiTHV4ZW1ib3VyZyIsIk1hbHRhIiwiTmV0aGVybGFuZHMiLCJQb2xhbmQiLCJQb3J0dWdhbCIsIlJvbWFuaWEiLCJTbG92YWsgUmVwdWJsaWMiLCJTbG92ZW5pYSIsIlNwYWluIiwiU3dlZGVuIiwiR3JlYXQgQnJpdGFpbiIsIkVBIGNoYW5naW5nIGNvbXAuIiwiRXVybyBBcmVhIDE5IikscmVnaWphPWMoIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJIUiIsIk90aGVyIEVVIiwiQ0VFIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIkNFRSIsIkNFRSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkVBIGNoYW5naW5nIGNvbXAuIiwiRXVybyBBcmVhIDE5IikpDQpwb20gPC0gcG9tICU+JSBsZWZ0X2pvaW4ocmVnLGJ5PSJyZWZfYXJlYSIpICU+JSBncm91cF9ieShkYXR1bSxyZWdpamEpICU+JSBzdW1tYXJpc2UoY2xpZnM9bWVhbihvYnN2YWx1ZSxuYS5ybT1UKSkNCmdncGxvdChwb20sYWVzKHg9ZGF0dW0seT1jbGlmcyxjb2w9cmVnaWphKSkgKyBnZW9tX2xpbmUoKSArIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyBsYWJzKHg9IiIseT0iQ0xJRlMgaW5kZWtzIikNCnJtKHBvbSkNCmBgYA0KDQojIyMgNS4yLiBFdXJvc3RhdA0KDQpFdXJvc3RhdCBpc3RvIGltYSBzdm9qIHBha2V0IHphIHByaXN0dXAgUi1hIG5hIG5qaWhvdm8gW3NrbGFkacWhdGUgcG9kYXRha2FdKGh0dHBzOi8vZWMuZXVyb3BhLmV1L2V1cm9zdGF0L2RhdGEvZGF0YWJhc2UpLiBLb2QgbmppaCBqZSBwcmlzdHVwIG1hbG8gZHJ1a8SNaWplIG9yZ2FuaXppcmFuLCB0YWtvIGRhIG5hanByaWplIHRyZWJhIHNwZWNpZmljaXJhdGkgdGFibGljdSBuYSBrb2p1IHNlIHNwYWphbW8gLSBbcHJpbWplciB6YSBCRFBdKGh0dHBzOi8vYXBwc3NvLmV1cm9zdGF0LmVjLmV1cm9wYS5ldS9udWkvc2hvdy5kbz9kYXRhc2V0PW5hbXFfMTBfZ2RwJmxhbmc9ZW4pLg0KDQpgYGB7ciwgbWVzc2FnZT1GfQ0KbGlicmFyeShldXJvc3RhdCkNCiMgMS4xLiBZT1kgc3RvcGEgcmFzdGEgQkRQLWENCnBvbTEgPC0gZ2V0X2V1cm9zdGF0KGlkPSJuYW1xXzEwX2dkcCIpICU+JSBmaWx0ZXIoZ2VvPT0iSFIiICYgbmFfaXRlbT09IkIxR1EiICYgc19hZGo9PSJOU0EiICYgdW5pdD09IkNMVjEwX01OQUMiKSAlPiUgc2VsZWN0KHRpbWUsYmRwPXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQojIDEuMi4gRG9wcmlub3MgLSBwb3Ryb8WhbmphIGt1xIdhbnN0YXZhDQpwb20yIDwtIGdldF9ldXJvc3RhdChpZD0ibmFtcV8xMF9nZHAiKSAlPiUgZmlsdGVyKGdlbz09IkhSIiAmIG5hX2l0ZW09PSJQMzFfUzE0X1MxNSIgJiBzX2Fkaj09Ik5TQSIgJiB1bml0PT0iQ0xWMTBfTU5BQyIpICU+JSBzZWxlY3QodGltZSxjX2hoPXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkNCg0KIyAxLjMuIERvcHJpbm9zIC0gcG90cm/FoW5qYSBkcsW+YXZlDQpwb20zIDwtIGdldF9ldXJvc3RhdChpZD0ibmFtcV8xMF9nZHAiKSAlPiUgZmlsdGVyKGdlbz09IkhSIiAmIG5hX2l0ZW09PSJQM19TMTMiICYgc19hZGo9PSJOU0EiICYgdW5pdD09IkNMVjEwX01OQUMiKSAlPiUgc2VsZWN0KHRpbWUsY19nb3Z0PXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkNCg0KIyAxLjQuIERvcHJpbm9zIC0gYnJ1dG8gaW52ZXN0aWNpamUNCnBvbTQgPC0gZ2V0X2V1cm9zdGF0KGlkPSJuYW1xXzEwX2dkcCIpICU+JSBmaWx0ZXIoZ2VvPT0iSFIiICYgbmFfaXRlbT09IlA1RyIgJiBzX2Fkaj09Ik5TQSIgJiB1bml0PT0iQ0xWMTBfTU5BQyIpICU+JSBzZWxlY3QodGltZSxpX2dyb3NzPXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkNCg0KIyAxLjUuIERvcHJpbm9zIC0gaXp2b3ogcm9iZSBpIHVzbHVnYQ0KcG9tNSA8LSBnZXRfZXVyb3N0YXQoaWQ9Im5hbXFfMTBfZ2RwIikgJT4lIGZpbHRlcihnZW89PSJIUiIgJiBuYV9pdGVtPT0iUDYiICYgc19hZGo9PSJOU0EiICYgdW5pdD09IkNMVjEwX01OQUMiKSAlPiUgc2VsZWN0KHRpbWUsZXg9dmFsdWVzKSAlPiUgYXJyYW5nZSh0aW1lKQ0KDQojIDEuNi4gRG9wcmlub3MgLSB1dm96IHJvYmUgaSB1c2x1Z2ENCnBvbTYgPC0gZ2V0X2V1cm9zdGF0KGlkPSJuYW1xXzEwX2dkcCIpICU+JSBmaWx0ZXIoZ2VvPT0iSFIiICYgbmFfaXRlbT09IlA3IiAmIHNfYWRqPT0iTlNBIiAmIHVuaXQ9PSJDTFYxMF9NTkFDIikgJT4lIHNlbGVjdCh0aW1lLGltPXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkNCg0KIyBvcGNpamEgMSAtIHV2aWplayBnbGVkYW1vIGdvZGnFoW5qZSBCRFAtb3ZlDQpwb20gPC0gbGVmdF9qb2luKHBvbTEscG9tMixieT0idGltZSIpICU+JSBsZWZ0X2pvaW4ocG9tMyxieT0idGltZSIpICU+JSBsZWZ0X2pvaW4ocG9tNCxieT0idGltZSIpICU+JSBsZWZ0X2pvaW4ocG9tNSxieT0idGltZSIpICU+JSBsZWZ0X2pvaW4ocG9tNixieT0idGltZSIpICU+JSBtdXRhdGUoZGF0dW0gPSBtYWtlX2RhdGUoaWZlbHNlKG1vbnRoKHRpbWUpPj0xMCx5ZWFyKHRpbWUpKzEseWVhcih0aW1lKSksaWZlbHNlKG1vbnRoKHRpbWUpPj0xMCwxLG1vbnRoKHRpbWUpKzMpLDEpIC0gMSwgYmRwX3kgPSAoYmRwICsgbGFnKGJkcCwxKSsgbGFnKGJkcCwyKSArIGxhZyhiZHAsMykpKjEwMDAwMDAgLCBjX2hoX3kgPSAoY19oaCArIGxhZyhjX2hoLDEpKyBsYWcoY19oaCwyKSArIGxhZyhjX2hoLDMpKSoxMDAwMDAwICwgY19nb3Z0X3kgPSAoY19nb3Z0ICsgbGFnKGNfZ292dCwxKSsgbGFnKGNfZ292dCwyKSArIGxhZyhjX2dvdnQsMykpKjEwMDAwMDAgLCBpX2dyb3NzX3kgPSAoaV9ncm9zcyArIGxhZyhpX2dyb3NzLDEpKyBsYWcoaV9ncm9zcywyKSArIGxhZyhpX2dyb3NzLDMpKSoxMDAwMDAwICwgZXhfeSA9IChleCArIGxhZyhleCwxKSsgbGFnKGV4LDIpICsgbGFnKGV4LDMpKSoxMDAwMDAwICwgaW1feSA9IChpbSArIGxhZyhpbSwxKSsgbGFnKGltLDIpICsgbGFnKGltLDMpKSoxMDAwMDAwKSAlPiUgbXV0YXRlKGRiZHAgPSAoYmRwX3kvbGFnKGJkcF95LDQpLTEpKjEwMCAsIGRvcF9jX2hoID0gKGNfaGhfeS9sYWcoY19oaF95LDQpLTEpKjEwMCpsYWcoY19oaF95LDQpL2xhZyhiZHBfeSw0KSAsIGRvcF9jX2dvdnQgPSAoY19nb3Z0X3kvbGFnKGNfZ292dF95LDQpLTEpKjEwMCpsYWcoY19nb3Z0X3ksNCkvbGFnKGJkcF95LDQpICwgZG9wX2lfZ3Jvc3MgPSAoaV9ncm9zc195L2xhZyhpX2dyb3NzX3ksNCktMSkqMTAwKmxhZyhpX2dyb3NzX3ksNCkvbGFnKGJkcF95LDQpICwgZG9wX2V4ID0gKGV4X3kvbGFnKGV4X3ksNCktMSkqMTAwKmxhZyhleF95LDQpL2xhZyhiZHBfeSw0KSAsIGRvcF9pbSA9IC0oaW1feS9sYWcoaW1feSw0KS0xKSoxMDAqbGFnKGltX3ksNCkvbGFnKGJkcF95LDQpKSAlPiUgc2VsZWN0KGRhdHVtLGRiZHAsZG9wX2NfaGgsZG9wX2NfZ292dCxkb3BfaV9ncm9zcyxkb3BfZXgsZG9wX2ltKSAlPiUgbmEub21pdCgpDQpjb2xuYW1lcyhwb20pIDwtIGMoImRhdHVtIiwiQkRQIiwiUG90cm/FoW5qYSBrdcSHYW5zdGF2YSIsIkphdm5hIHBvdHJvxaFuamEiLCJCcnV0byBpbnZlc3RpY2lqZSIsIkl6dm96IiwiVXZveiIpDQpwb20gPC0gcG9tICU+JSBnYXRoZXIoa2V5ID0gInZhcmlqYWJsYSIsdmFsdWUgPSAiaXpub3MiLC1kYXR1bSkNCmdncGxvdChwb20gJT4lIGZpbHRlcih2YXJpamFibGEhPSJCRFAiKSxhZXMoeD1kYXR1bSx5PWl6bm9zLGZpbGw9dmFyaWphYmxhKSkgKyBnZW9tX2NvbChwb3NpdGlvbj0ic3RhY2siKSArIGdlb21fcG9pbnQoZGF0YT1wb20gJT4lIGZpbHRlcih2YXJpamFibGE9PSJCRFAiKSxhZXMoeD1kYXR1bSx5PWl6bm9zKSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIGxhYnMoeD0iIix5PSIiKQ0Kcm0ocG9tMSxwb20yLHBvbTMscG9tNCxwb201LHBvbTYscG9tKQ0KYGBgDQoNCiMjIyA1LjMuIFN2amV0c2thIEJhbmthDQoNCktvZCBuamloIHByaXN0dXAgcG9kYWNpbWEgZnVua2Npb25pcmEgbmEgc2xpxI1hbiBuYcSNaW4ga2FvIGkga29kIEVDQi1hLCBnZGplIHN2YWtpIGluZGlrYXRvciBpbWEgamVkaW5zdHZlbmkga29kIC0gW3ByaW1qZXIgemEgaW5kaWthdG9yIHRyZ292aW5lIG5hIHRyxb5pxaF0dSBrYXBpdGFsYSB1ICVCRFAtYV0oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL0NNLk1LVC5UUkFELkdELlpTKS4NCg0KYGBge3J9DQpsaWJyYXJ5KHdic3RhdHMpDQpyZWcgPSBkYXRhLmZyYW1lKGN0cnk9YygiQVQiLCJCRSIsIkJHIiwiSFIiLCJDWSIsIkNaIiwiREsiLCJFRSIsIkZJIiwiRlIiLCJERSIsIkdSIiwiSFUiLCJJRSIsIklUIiwiTFYiLCJMVCIsIkxVIiwiTVQiLCJOTCIsIlBMIiwiUFQiLCJSTyIsIlNLIiwiU0kiLCJFUyIsIlNFIiwiR0IiLCJVMiIsIkk4IiksY291bnRyeT1jKCJBdXN0cmlhIiwiQmVsZ2l1bSIsIkJ1bGdhcmlhIiwiQ3JvYXRpYSIsIkN5cHJ1cyIsIkN6ZWNoIFJlcHVibGljIiwiRGVubWFyayIsIkVzdG9uaWEiLCJGaW5sYW5kIiwiRnJhbmNlIiwiR2VybWFueSIsIkdyZWVjZSIsIkh1bmdhcnkiLCJJcmVsYW5kIiwiSXRhbHkiLCJMYXR2aWEiLCJMaXRodWFuaWEiLCJMdXhlbWJvdXJnIiwiTWFsdGEiLCJOZXRoZXJsYW5kcyIsIlBvbGFuZCIsIlBvcnR1Z2FsIiwiUm9tYW5pYSIsIlNsb3ZhayBSZXB1YmxpYyIsIlNsb3ZlbmlhIiwiU3BhaW4iLCJTd2VkZW4iLCJHcmVhdCBCcml0YWluIiwiRUEgY2hhbmdpbmcgY29tcC4iLCJFdXJvIEFyZWEgMTkiKSxyZWdpamE9YygiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIkhSIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiQ0VFIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIk90aGVyIEVVIiwiQ0VFIiwiQ0VFIiwiQ0VFIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiRUEgY2hhbmdpbmcgY29tcC4iLCJFdXJvIEFyZWEgMTkiKSkNCnN0b2Nrc190cmFkZWQgPC0gd2IoaW5kaWNhdG9yID0gIkNNLk1LVC5UUkFELkdELlpTIikNCnBvbSA8LSBzdG9ja3NfdHJhZGVkICU+JSBmaWx0ZXIoaXNvMmMgJWluJSByZWckY3RyeSAmIGRhdGUgJWluJSBjKCIyMDE0IiwiMjAxNSIsIjIwMTYiLCIyMDE3IiwiMjAxOCIpKSAlPiUgc2VsZWN0KGRhdGUsY3RyeT1pc28yYyx2YWx1ZSkgJT4lIGdyb3VwX2J5KGN0cnkpICU+JSBzdW1tYXJpc2UodmFsdWU9bWVhbih2YWx1ZSxuYS5ybT1UKSkgJT4lIGxlZnRfam9pbihyZWcsYnk9ImN0cnkiKSAlPiUgZmlsdGVyKGN0cnkhPSJVUyIpICU+JSBtdXRhdGUocmVnaWphPWlmZWxzZShyZWdpamE9PSJDRUUiLCJaZW1samUgU0lFIixpZmVsc2UocmVnaWphPT0iT3RoZXIgRVUiLCJPc3RhbGUgRVUgemVtbGplIiwiSFIiKSkpDQpnZ3Bsb3QocG9tLGFlcyh4PXJlb3JkZXIoY3RyeSwtdmFsdWUpLHk9dmFsdWUpKSArIGdlb21fY29sKGFlcyhmaWxsPXJlZ2lqYSkpICsgbGFicyh4PSIiLHk9IiIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCnJtKHJlZyxzdG9ja3NfdHJhZGVkLHBvbSkNCmBgYA0KDQojIyMgNS40LiBPRUNEDQoNCkplZGFuIGZvcmEgcHJpbWplciBtb2d1xIdub3N0aSBSLWEsIHN1IHJlenVsdGF0aSBmaW5hbmNpanNrZSBwaXNtZW5vc3RpIGtvanUgcHJvdm9kaSBPRUNEIGkga29qdSBvYmphbHZqdWplIFt1IFBERi11XShodHRwOi8vd3d3Lm9lY2Qub3JnL2RhZi9maW4vZmluYW5jaWFsLWVkdWNhdGlvbi9PRUNELUlORkUtSW50ZXJuYXRpb25hbC1TdXJ2ZXktb2YtQWR1bHQtRmluYW5jaWFsLUxpdGVyYWN5LUNvbXBldGVuY2llcy5wZGYpLiBQb3N0b2ppIHBha2V0IHUgUi11IGtvamkgaW1hIHNwb29ibm9zdCDEjWl0YW5qYSBQREYtb3ZhIGkgdXNwaW8gamUgdcSNaXRhdGkgb3ZlIHBvZGF0a2Ugc2Egc2xpa2UgbmEgc3RyYW5pY2kgMTAuDQoNCmBgYHtyfQ0KbGlicmFyeSh0YWJ1bGl6ZXIpDQpwaXNtZW5vc3RfdGFibGljYSA8LSBleHRyYWN0X3RhYmxlcygiaHR0cDovL3d3dy5vZWNkLm9yZy9kYWYvZmluL2ZpbmFuY2lhbC1lZHVjYXRpb24vT0VDRC1JTkZFLUludGVybmF0aW9uYWwtU3VydmV5LW9mLUFkdWx0LUZpbmFuY2lhbC1MaXRlcmFjeS1Db21wZXRlbmNpZXMucGRmIikNCnRlbXAgPC0gcGlzbWVub3N0X3RhYmxpY2FbWzNdXQ0KdGVtcCA8LSBhcy5kYXRhLmZyYW1lKHRlbXApDQpjb2xuYW1lcyh0ZW1wKTwtYygiY3RyeV9zY29yZSIsImtub3dsZWRnZV9zY29yZSIsImJlaGF2aW91cl9zY29yZSIsImF0dGl0dWRlX3Njb3JlIikNCnRlbXAgPC0gdGVtcCAlPiUgc2VwYXJhdGUoY3RyeV9zY29yZSxjKCJjb3VudHJ5IiwiZmluYW5jaWFsX2tub3dsZWRnZSIpLCIgXFwoIikgJT4lIG11dGF0ZShmaW5hbmNpYWxfa25vd2xlZGdlPXN0cl9yZXBsYWNlKGZpbmFuY2lhbF9rbm93bGVkZ2UsIlxcKSIsIiIpKSAlPiUgbXV0YXRlKGZpbmFuY2lhbF9rbm93bGVkZ2U9YXMubnVtZXJpYyhmaW5hbmNpYWxfa25vd2xlZGdlKSxrbm93bGVkZ2Vfc2NvcmU9YXMuY2hhcmFjdGVyKGtub3dsZWRnZV9zY29yZSksYmVoYXZpb3VyX3Njb3JlPWFzLmNoYXJhY3RlcihiZWhhdmlvdXJfc2NvcmUpLGF0dGl0dWRlX3Njb3JlPWFzLmNoYXJhY3RlcihhdHRpdHVkZV9zY29yZSkpICU+JSBtdXRhdGUoa25vd2xlZGdlX3Njb3JlPWFzLm51bWVyaWMoa25vd2xlZGdlX3Njb3JlKSxiZWhhdmlvdXJfc2NvcmU9YXMubnVtZXJpYyhiZWhhdmlvdXJfc2NvcmUpLGF0dGl0dWRlX3Njb3JlPWFzLm51bWVyaWMoYXR0aXR1ZGVfc2NvcmUpKQ0KZmluYW5jaWpza2FfcGlzbWVub3N0IDwtIHRlbXANCnJlZyA9IGRhdGEuZnJhbWUoY3RyeT1jKCJBVCIsIkJFIiwiQkciLCJIUiIsIkNZIiwiQ1oiLCJESyIsIkVFIiwiRkkiLCJGUiIsIkRFIiwiR1IiLCJIVSIsIklFIiwiSVQiLCJMViIsIkxUIiwiTFUiLCJNVCIsIk5MIiwiUEwiLCJQVCIsIlJPIiwiU0siLCJTSSIsIkVTIiwiU0UiLCJHQiIsIlUyIiwiVVMiKSxjb3VudHJ5PWMoIkF1c3RyaWEiLCJCZWxnaXVtIiwiQnVsZ2FyaWEiLCJDcm9hdGlhIiwiQ3lwcnVzIiwiQ3plY2ggUmVwdWJsaWMiLCJEZW5tYXJrIiwiRXN0b25pYSIsIkZpbmxhbmQiLCJGcmFuY2UiLCJHZXJtYW55IiwiR3JlZWNlIiwiSHVuZ2FyeSIsIklyZWxhbmQiLCJJdGFseSIsIkxhdHZpYSIsIkxpdGh1YW5pYSIsIkx1eGVtYm91cmciLCJNYWx0YSIsIk5ldGhlcmxhbmRzIiwiUG9sYW5kIiwiUG9ydHVnYWwiLCJSb21hbmlhIiwiU2xvdmFrIFJlcHVibGljIiwiU2xvdmVuaWEiLCJTcGFpbiIsIlN3ZWRlbiIsIlVuaXRlZCBLaW5nZG9tIiwiRUEgY2hhbmdpbmcgY29tcC4iLCJVbml0ZWQgU3RhdGVzIikscmVnaWphPWMoIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJIUiIsIk90aGVyIEVVIiwiQ0VFIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIkNFRSIsIkNFRSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkVBIGNoYW5naW5nIGNvbXAuIiwiVVMiKSkNCnBvbSA8LSBmaW5hbmNpanNrYV9waXNtZW5vc3QgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgcmVnJGNvdW50cnkpICU+JSBsZWZ0X2pvaW4ocmVnLGJ5PSJjb3VudHJ5IikNCmdncGxvdChwb20sYWVzKHg9cmVvcmRlcihjdHJ5LC1maW5hbmNpYWxfa25vd2xlZGdlKSx5PWZpbmFuY2lhbF9rbm93bGVkZ2UpKSArIGdlb21fY29sKGFlcyhmaWxsPXJlZ2lqYSkpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZmluYW5jaWpza2FfcGlzbWVub3N0JGZpbmFuY2lhbF9rbm93bGVkZ2VbZmluYW5jaWpza2FfcGlzbWVub3N0JGNvdW50cnk9PSJBdmVyYWdlLCBhbGwgY291bnRyaWVzIl0pICsgbGFicyh4PSIiLHk9IkZpbmFuY2lqc2thIHBpc21lbm9zdCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQ0Kcm0ocGlzbWVub3N0X3RhYmxpY2EsdGVtcCxmaW5hbmNpanNrYV9waXNtZW5vc3QscG9tKQ0KYGBgDQoNCiMjIyA1LjUuIEVJT1BBIHBvZGFjaQ0KDQpFSU9QQSBuaWplIG5hcHJlZG5hIGthbyBFQ0IgaWxpIEVVUk9TVEFUIHUgb2JqYXZpIHBvZGF0YWthIGkgb2JqYXZsanVqZSBpaCBbdSBleGNlbGltYV0oaHR0cHM6Ly93d3cuZWlvcGEuZXVyb3BhLmV1L3Rvb2xzLWFuZC1kYXRhL2luc3VyYW5jZS1zdGF0aXN0aWNzX2VuKSwgbm8gaSB6YSB0byBpbWFtbyBzaXN0ZW0uDQoNCg0KIyMgNi4gUHJpcHJlbWEgcG9kYXRha2ENCg0KVmHFvm5vIGplIG5hZ2xhc2l0aSBkYSBqZSB6YSBrdmFsaXRldG51IGFuYWxpenUgbnXFvm5hIGRvYnJhIHByaXByZW1hIHBvZGF0YWthLiBQcmVtYSBbaXN0cmHFvml2YW5qdSBDcm93ZEZsb3dlci1hXShodHRwczovL3d3dy5mb3JiZXMuY29tL3NpdGVzL2dpbHByZXNzLzIwMTYvMDMvMjMvZGF0YS1wcmVwYXJhdGlvbi1tb3N0LXRpbWUtY29uc3VtaW5nLWxlYXN0LWVuam95YWJsZS1kYXRhLXNjaWVuY2UtdGFzay1zdXJ2ZXktc2F5cy8jNWNmMzc5NTZmNjM3KSwgdSAqRGF0YSBzY2llbmNlLXUqIHNlICoqODAlIHZyZW1lbmEgc3ZvZGkgbmEgcHJpcHJlbXUgcG9kYXRha2EqKiwgxaF0byBqZSB1amVkbm8gaSBuYWptYW5qZSB6YW5pbWxqaXYgZGlvIHByb2Nlc2EuDQoNCiFbXShjaXNjZW5qZV9wb2RhdGFrYV9hbmtldGEuUE5HKQ0KDQojIyMgNi4xLiBUaWR5IHN0cnVrdHVyYSBwb2RhdGFrYQ0KDQpLYWtvIGJpIHNlIHZyaWplbWUgcG90cmVibm8gemEgb2JyYWR1IHBvZGF0YWthLCBhbGkgaSB2cmlqZW1lIHphIGFuYWxpenUgcG9kYXRha2Egc21hbmppbG8sIG51xb5ubyBqZSBkYSBwb2RhY2kgYnVkdSB1IHRpZHkgZm9ybWF0dS4NCg0KIVtdKFRpZHlfZGF0YS5QTkcpDQoNCiMjIyA2LjIuIEZpbmFuY2lqc2tpIHJhxI11bmkNCg0KRmluYW5jaWpza2UgcmHEjXVuZSBkb2JpdmFtbyBuYSBrcmFqbmplIG5lc3RydWt0dXJpcmFuIG5hxI1pbiBpIGtvamkgc2UgbmFsYXplIFtvdmRqZV0oRDpcbWJhbWJhXERBVEFcRmluYW5jaWpza2lfcmFjdW5pKS4gT25vIMWhdG8gUiBvbW9ndcSHdWplIGplIHNrbGFwYW5qZSB1IDEgYmF6dSBrb2phIHNlIG9uZGEgbW/FvmUga29yaXN0aXRpIHphIGFuYWxpenUgaSBuZSBzYW1vIHRvIG5lZ28gamUgbmEgdGFqIG5hxI1pbiA5NzBNQiBwb2RhdGFrYSB1IGV4Y2VsaW1hIHByZXR2b3Jlbm8gdSAyLjdNQiB2ZWxpa2kgZGF0YWZyYW1lLg0KDQpPdmFrdmEgc3RydWt0dXJhIHBvZGF0YWthIG9tb2d1xId1amUgc2xqZWRlxIdlIHNsaWtlOg0KDQpgYGB7cn0NCmxpYnJhcnkoaWdyYXBoKQ0KIyBTbGlrYSAxMS4gTXJlxb5hIHRyYW5zYWtjaWphICMjIyMNCmxvYWQoIkZpblJhY3VuaS5SZGEiKQ0KdDAgPC0gYXMuRGF0ZSgiMjAxMi0wMy0zMSIpDQp0MSA8LSBhcy5EYXRlKCIyMDE5LTA2LTMwIikNCmJyX2RhbmEgPC0gYXMubnVtZXJpYyh0MS10MCkNCiMgYW51YWxpemlyYW5pIHJhc3Qgc2VrdG9yYSBuYSB0ZW1lbGp1IHRyYW5zYWtjaWphIGl6bWXEkXUgdDAgaSB0MQ0KIyBwb8SNZXRuYSBzdGFuamENCnBvbTExIDwtIGZpbmFuY2lqc2tpX3JhY3VuaSAlPiUgbXV0YXRlKHNla3Rvcl9tYiA9IGlmZWxzZShzZWt0b3JfbWI9PSJPc3RhbGkgZmluYW5jaWpza2kgcG9zcmVkbmljaSIsIk9zdGFsZSBGSSIsc2VrdG9yX21iKSkgJT4lIGdyb3VwX2J5KGRhdHVtLHNla3Rvcl9tYikgJT4lIGZpbHRlcih2cnN0YV9pem5vc2E9PSJCQUwgVCIgJiB2cnN0YV9pbW92aW5lPT0iVG90YWwiICYgcmF6aW5hPT0iQXNzZXRzIiAmICFzZWt0b3IgJWluJSBjKCJUT1RBTCIsIk5BIikgJiAhcHJvdHVzdHJhbmEgJWluJSBjKCJUT1RBTCIsIk5BIikgJiBkYXR1bT09dDApICU+JSBzdW1tYXJpc2Uoc3RhbmphPXN1bShpem5vcyxuYS5ybSA9IFQpKQ0KIyB1a3VwbmUgdHJhbnNha2NpamUgcG8gc2VrdG9yaW1hICh6YSBpenJhxI11biByYXN0YSBuYSB0ZW1lbGp1IHRyYW5zYWtjaWphKQ0KcG9tMTIgPC0gZmluYW5jaWpza2lfcmFjdW5pICU+JSBtdXRhdGUoc2VrdG9yX21iID0gaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT3N0YWxlIEZJIixzZWt0b3JfbWIpKSAlPiUgZ3JvdXBfYnkoc2VrdG9yX21iKSAlPiUgZmlsdGVyKHZyc3RhX2l6bm9zYT09IlRSQU5TIFQiICYgdnJzdGFfaW1vdmluZT09IlRvdGFsIiAmIHJhemluYT09IkFzc2V0cyIgJiAhc2VrdG9yICVpbiUgYygiVE9UQUwiLCJOQSIpICYgIXByb3R1c3RyYW5hICVpbiUgYygiVE9UQUwiLCJOQSIpICYgZGF0dW0+dDApICU+JSBzdW1tYXJpc2UoY3VtX3RyYW5zPXN1bShpem5vcyxuYS5ybSA9IFQpKQ0KIyBpenJhxI11biByYXN0YSBuYSB0ZW1lbGp1IHRyYW5zYWtjaWphDQpwb20xIDwtIGxlZnRfam9pbihwb20xMSxwb20xMixieT0ic2VrdG9yX21iIikgJT4lIG11dGF0ZShjdW1fcmFzdD0oKGN1bV90cmFucykvc3RhbmphKSoxMDApICU+JSBtdXRhdGUoYW5fcmFzdD0oKDErY3VtX3Jhc3QvMTAwKV4oMzY1L2JyX2RhbmEpLTEpKjEwMCkNCiMgZG9wcmlub3NpIHByb3R1c3RyYW5raSBhbnVhbGl6aXJhbm9tIHJhc3R1IHNla3RvcmEgbmEgdGVtZWxqdSB0cmFuc2FrY2lqYSBpem1lxJF1IHQwIGkgdDENCiMga3VtdWxhdGl2bmUgdHJhbnNha2NpamUgcG8gcHJvdHVzdHJhbmNpDQpwb20yIDwtIGZpbmFuY2lqc2tpX3JhY3VuaSAlPiUgbXV0YXRlKHNla3Rvcl9tYiA9IGlmZWxzZShzZWt0b3JfbWI9PSJPc3RhbGkgZmluYW5jaWpza2kgcG9zcmVkbmljaSIsIk9zdGFsZSBGSSIsc2VrdG9yX21iKSAsIHByb3R1c3RyYW5hX21iID0gaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iT3N0YWxpIGZpbmFuY2lqc2tpIHBvc3JlZG5pY2kiLCJPc3RhbGUgRkkiLHByb3R1c3RyYW5hX21iKSkgJT4lIGdyb3VwX2J5KHNla3Rvcl9tYixwcm90dXN0cmFuYV9tYikgJT4lIGZpbHRlcih2cnN0YV9pem5vc2E9PSJUUkFOUyBUIiAmIHZyc3RhX2ltb3ZpbmU9PSJUb3RhbCIgJiByYXppbmE9PSJBc3NldHMiICYgIXNla3RvciAlaW4lIGMoIlRPVEFMIiwiTkEiKSAmICFwcm90dXN0cmFuYSAlaW4lIGMoIlRPVEFMIiwiTkEiKSAmIGRhdHVtPnQwKSAlPiUgc3VtbWFyaXNlKGN1bV90cmFuc19zZWt0PXN1bShpem5vcyxuYS5ybSA9IFQpKQ0KIyBza2xhcGFuamUgaSByYcSNdW5hbmplIHN0b3BhIHJhc3RhDQpwb20gPC0gbGVmdF9qb2luKHBvbTIscG9tMSxieT1jKCJzZWt0b3JfbWIiKSkgJT4lIG11dGF0ZShjdW1fZG9wX3Nla3QgPSAoY3VtX3RyYW5zX3Nla3Qvc3RhbmphKSoxMDApICU+JSBtdXRhdGUoZG9wcmlub3NfdHJhbnM9KCgxK2N1bV9kb3Bfc2VrdC8xMDApXigzNjUvYnJfZGFuYSktMSkqMTAwKQ0KDQojIGRlZmluaXJhbmplIGJyaWRvdmENCmJyaWRvdmkgPC0gcG9tICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShzZWt0b3JfbWI9aWZlbHNlKHNla3Rvcl9tYj09IlBvZHV6ZcSHYSIsIlBPRCIsaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsZSBGSSIsIk9GSSIsaWZlbHNlKHNla3Rvcl9tYj09IkNlbnRyYWxuYSBiYW5rYSIsIkNCIixpZmVsc2Uoc2VrdG9yX21iPT0iS3JlZGl0bmUgaW5zdGl0dWNpamUiLCJLSSIsaWZlbHNlKHNla3Rvcl9tYj09IkludmVzdGljaWpza2kgZm9uZG92aSIsIklGIixpZmVsc2Uoc2VrdG9yX21iPT0iT3NpZ3VyYW5qYSIsIk9TIixpZmVsc2Uoc2VrdG9yX21iPT0iTWlyb3ZpbnNraSBmb25kb3ZpIiwiTUYiLGlmZWxzZShzZWt0b3JfbWI9PSJEcsW+YXZhIiwiRFLFvSIsaWZlbHNlKHNla3Rvcl9tYj09IlN0YW5vdm5pxaF0dm8iLCJLVcSGIixpZmVsc2Uoc2VrdG9yX21iPT0iSW5vemVtc3R2byIsIklOTyIsaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT0ZQIiwiTkEiKSkpKSkpKSkpKSkpICU+JSBtdXRhdGUocHJvdHVzdHJhbmFfbWI9aWZlbHNlKHByb3R1c3RyYW5hX21iPT0iUG9kdXplxIdhIiwiUE9EIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJPc3RhbGUgRkkiLCJPRkkiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09IkNlbnRyYWxuYSBiYW5rYSIsIkNCIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJLcmVkaXRuZSBpbnN0aXR1Y2lqZSIsIktJIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJJbnZlc3RpY2lqc2tpIGZvbmRvdmkiLCJJRiIsaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iT3NpZ3VyYW5qYSIsIk9TIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJNaXJvdmluc2tpIGZvbmRvdmkiLCJNRiIsaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iRHLFvmF2YSIsIkRSxb0iLGlmZWxzZShwcm90dXN0cmFuYV9tYj09IlN0YW5vdm5pxaF0dm8iLCJLVcSGIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJJbm96ZW1zdHZvIiwiSU5PIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJPc3RhbGkgZmluYW5jaWpza2kgcG9zcmVkbmljaSIsIk9GUCIsIk5BIikpKSkpKSkpKSkpKQ0KDQojIGRlZmluaXJhbmplIHZyaG92YSANCnZyaG92aSA8LSBwb20xICU+JSB1bmdyb3VwKCkgJT4lIG11dGF0ZShzZWt0b3JfbWI9aWZlbHNlKHNla3Rvcl9tYj09IlBvZHV6ZcSHYSIsIlBPRCIsaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsZSBGSSIsIk9GSSIsaWZlbHNlKHNla3Rvcl9tYj09IkNlbnRyYWxuYSBiYW5rYSIsIkNCIixpZmVsc2Uoc2VrdG9yX21iPT0iS3JlZGl0bmUgaW5zdGl0dWNpamUiLCJLSSIsaWZlbHNlKHNla3Rvcl9tYj09IkludmVzdGljaWpza2kgZm9uZG92aSIsIklGIixpZmVsc2Uoc2VrdG9yX21iPT0iT3NpZ3VyYW5qYSIsIk9TIixpZmVsc2Uoc2VrdG9yX21iPT0iTWlyb3ZpbnNraSBmb25kb3ZpIiwiTUYiLGlmZWxzZShzZWt0b3JfbWI9PSJEcsW+YXZhIiwiRFLFvSIsaWZlbHNlKHNla3Rvcl9tYj09IlN0YW5vdm5pxaF0dm8iLCJLVcSGIixpZmVsc2Uoc2VrdG9yX21iPT0iSW5vemVtc3R2byIsIklOTyIsaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT0ZQIiwiTkEiKSkpKSkpKSkpKSkpICU+JSBtdXRhdGUoaGFuZmE9aWZlbHNlKHNla3Rvcl9tYiAlaW4lIGMoIklGIiwiTUYiLCJPUyIsIk9GSSIsIk9GUCIpLCJkYSIsIm5lIikpICU+JSBmaWx0ZXIoc2VrdG9yX21iIT0iQ0IiKSAlPiUgc2VsZWN0KHNla3Rvcl9tYixyYXN0X3RyYW5zPWFuX3Jhc3QsaGFuZmEpDQoNCiMgdXppbWFuamUgc2FtbyBicmlkb3ZhIGtvamkgc3UgcmF6bGnEjWl0byBvZCAwJSBpIHNhbW8gb25paCBicmlkb3ZhIGtvamkgaW1hanUgdmV6ZSBzYSBIQU5GQS1pbmltIHNla3RvcmltYQ0KYnJpZG92aSA8LSBicmlkb3ZpICU+JSBmaWx0ZXIoKGRvcHJpbm9zX3RyYW5zPD0tMC41IHwgZG9wcmlub3NfdHJhbnM+PTAuNSkgJiAoc2VrdG9yX21iICVpbiUgYygiTUYiLCJPUyIsIklGIiwiT0ZJIiwiT0ZQIikgfCBwcm90dXN0cmFuYV9tYiAlaW4lIGMoIk1GIiwiT1MiLCJJRiIsIk9GSSIsIk9GUCIpKSkgJT4lIGZpbHRlcihzZWt0b3JfbWIhPXByb3R1c3RyYW5hX21iKQ0KDQojIGtyZWlyYW5qZSBtcmXFvm5vZyBvYmpla3RhDQpncmFmIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gYnJpZG92aSwgdmVydGljZXMgPSB2cmhvdmksIGRpcmVjdGVkID0gVCkNCiMgcG9zdGF2bGphbmplIGJvamUgdnJoYSAoYWtvIHJhc3RhbyB6ZWxlbm8sIGFrbyBwYW8gb25kYSBjcnZlbm8pDQpWKGdyYWYpJGNvbG9yIDwtIGlmZWxzZShWKGdyYWYpJHJhc3RfdHJhbnMgPD0oLTEwKSwgImZpcmVicmljazQiLCBpZmVsc2UoVihncmFmKSRyYXN0X3RyYW5zIDw9KC01KSwib3JhbmdlcmVkIixpZmVsc2UoVihncmFmKSRyYXN0X3RyYW5zPD0wLCJsaWdodHNhbG1vbiIsaWZlbHNlKFYoZ3JhZikkcmFzdF90cmFucyA8PTUsImdvbGQiLGlmZWxzZShWKGdyYWYpJHJhc3RfdHJhbnMgPD0xMCwieWVsbG93Z3JlZW4iLCJzZWFncmVlbjQiKSkpKSkNCiMgcG9zdGF2bGphbmplIGJvamUgYnJpZGEgKGFrbyByYXNsYSB6ZWxlbm8sIGFrbyBwYWxhIGNydmVubykNCkUoZ3JhZikkY29sb3IgPC0gaWZlbHNlKEUoZ3JhZikkZG9wcmlub3NfdHJhbnMgPD0oLTUpLCAiZmlyZWJyaWNrNCIsIGlmZWxzZShFKGdyYWYpJGRvcHJpbm9zX3RyYW5zIDw9KC0yLjUpLCJvcmFuZ2VyZWQiLGlmZWxzZShFKGdyYWYpJGRvcHJpbm9zX3RyYW5zIDw9MCwibGlnaHRzYWxtb24iLGlmZWxzZShFKGdyYWYpJGRvcHJpbm9zX3RyYW5zIDw9Mi41LCJnb2xkIixpZmVsc2UoRShncmFmKSRkb3ByaW5vc190cmFucyA8PTUsInllbGxvd2dyZWVuIiwic2VhZ3JlZW40IikpKSkpDQojIHNsaWthIG1yZcW+ZSBwb3ZlemFub3N0aSAtIGplZG5ha2UgdmVsacSNaW5lIHZyaG92YQ0KcGxvdChncmFmLCB2ZXJ0ZXguc2l6ZSA9IDI1LCBlZGdlLmFycm93LnNpemUgPSAwLjUsIGxheW91dD1sYXlvdXRfbmljZWx5KGdyYWYpLCB2ZXJ0ZXgubGFiZWwuY29sb3IgPSAiYmxhY2siLCB2ZXJ0ZXguZnJhbWUuY29sb3I9TkEsdmVydGV4LnNoYXBlPWlmZWxzZShWKGdyYWYpJGhhbmZhPT0iZGEiLCJzcXVhcmUiLCJjaXJjbGUiKSkNCiMgQWRkIGEgbGVnZW5kDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9YygiPC1vbzstMTBdIDsgPC0xMDstNV0iLCAiPC0xMDstNV0gOyA8LTU7LTIsNV0iLCI8LTU7MF0gOyA8LTIsNTstMCw1XSIsIjwwOzVdIDsgWzAsNTsyLDVdIiwiPDU7MTBdIDsgPDIsNTs1XSIsIjwxMDsrb28+IDsgPDU7K29vPiIpLCBmaWxsPWMoImZpcmVicmljazQiLCAib3JhbmdlcmVkIiwibGlnaHRzYWxtb24iLCJnb2xkIiwieWVsbG93Z3JlZW4iLCJzZWFncmVlbjQiKSwgdGl0bGUgPSAiVnJob3ZpIChyYXN0IG5hIHRlbWVsanUgdHJhbnNha2NpamEpIDsgXG4gU3RyZWxpY2UgKGRvcHJpbm9zaSByYXN0dSkiLCBjZXg9MC44LCBidHk9Im4iKQ0KIyBicmlzYW5qZSBwcml2cmVtZW5paCB0YWJsaWNhDQpybSh0MCx0MSxicl9kYW5hLHBvbTEscG9tMixwb20xMSxwb20xMixwb20sYnJpZG92aSx2cmhvdmksZ3JhZikNCg0KIyBTbGlrYSAxMi4gTXJlxb5hIHN0YW5qYSAjIyMjDQp6YWRuamlfZGF0dW0gPC0gIjIwMTktMDYtMzAiDQojIHZlbGnEjWluYSBkaXJla3RuZSBwb3ZlemFub3N0aSB1IGFwc29sdXRub2ogdnJpamVkbm9zdGkNCnBvbTEgPC0gZmluYW5jaWpza2lfcmFjdW5pICU+JSBtdXRhdGUoc2VrdG9yX21iID0gaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT3N0YWxlIEZJIixzZWt0b3JfbWIpICwgcHJvdHVzdHJhbmFfbWIgPSBpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJPc3RhbGkgZmluYW5jaWpza2kgcG9zcmVkbmljaSIsIk9zdGFsZSBGSSIscHJvdHVzdHJhbmFfbWIpKSAlPiUgZmlsdGVyKGRhdHVtPT16YWRuamlfZGF0dW0gJiB2cnN0YV9pem5vc2E9PSJCQUwgVCIgJiB2cnN0YV9pbW92aW5lPT0iVG90YWwiICYgcmF6aW5hPT0iQXNzZXRzIiAmICFzZWt0b3IgJWluJSBjKCJUT1RBTCIsIk5BIikgJiAhcHJvdHVzdHJhbmEgJWluJSBjKCJUT1RBTCIsIk5BIikpICU+JSBncm91cF9ieShzZWt0b3JfbWIscHJvdHVzdHJhbmFfbWIpICU+JSBzdW1tYXJpc2UoaXpub3M9c3VtKGl6bm9zLG5hLnJtID0gVCkvMTAwMDAwMDAwMCkNCiMgdWt1cG5hIHZlbGnEjWluYSBzZWt0b3JhIChvbmEgxIdlIG5hbSBzbHXFvml0aSBkYSByZWxhdGl2aXppcmFtbyBwb3ZlemFub3N0IGkgb2JvamltbyB1IDQgYm9qZSkNCnBvbTIgPC0gZmluYW5jaWpza2lfcmFjdW5pICU+JSBtdXRhdGUoc2VrdG9yX21iID0gaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT3N0YWxlIEZJIixzZWt0b3JfbWIpKSAlPiUgZmlsdGVyKGRhdHVtPT16YWRuamlfZGF0dW0gJiB2cnN0YV9pem5vc2E9PSJCQUwgVCIgJiB2cnN0YV9pbW92aW5lPT0iVG90YWwiICYgcmF6aW5hPT0iQXNzZXRzIiAmICFzZWt0b3IgJWluJSBjKCJUT1RBTCIsIk5BIikgJiBwcm90dXN0cmFuYSAlaW4lIGMoIlRPVEFMIikpICU+JSBncm91cF9ieShzZWt0b3JfbWIpICU+JSBzdW1tYXJpc2UodmVsaWNpbmFfc2VrdG9yPXN1bShpem5vcyxuYS5ybSA9IFQpLzEwMDAwMDAwMDApDQojIHVrdXBuYSB2ZWxpxI1pbmEgcHJvdHVzdHJhbmUgKG9uYSDEh2UgbmFtIHNsdcW+aXRpIGRhIHJlbGF0aXZpemlyYW1vIHBvdmV6YW5vc3QgaSBrcmVpcmFtbyBkZWJsamludSBsaW5pamUpDQpwb20zIDwtIGZpbmFuY2lqc2tpX3JhY3VuaSAlPiUgbXV0YXRlKHByb3R1c3RyYW5hX21iID0gaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iT3N0YWxpIGZpbmFuY2lqc2tpIHBvc3JlZG5pY2kiLCJPc3RhbGUgRkkiLHByb3R1c3RyYW5hX21iKSkgJT4lIGZpbHRlcihkYXR1bT09emFkbmppX2RhdHVtICYgdnJzdGFfaXpub3NhPT0iQkFMIFQiICYgdnJzdGFfaW1vdmluZT09IlRvdGFsIiAmIHJhemluYT09IkFzc2V0cyIgJiAhcHJvdHVzdHJhbmEgJWluJSBjKCJUT1RBTCIsIk5BIikgJiBzZWt0b3IgJWluJSBjKCJUT1RBTCIpKSAlPiUgZ3JvdXBfYnkocHJvdHVzdHJhbmFfbWIpICU+JSBzdW1tYXJpc2UodmVsaWNpbmFfcHJvdHVzdHJhbmE9c3VtKGl6bm9zLG5hLnJtID0gVCkvMTAwMDAwMDAwMCkNCiMgdWt1cG5hIHZlbGnEjWluYSBpemxvxb5lbm9zdGkgc2VrdG9ydSBmaW5hbmNpanNraWggdXNsdWdhIChvbmEgxIdlIG5hbSBzbHXFvml0aSBkYSByZWxhdGl2aXppcmFtbyBwb3ZlemFub3N0IGkga3JlaXJhbW8gdmVsacSNaW51IGt1Z2xlIHphIG5lSEFORkEtaW5lIHZyaG92ZSkNCnBvbTQgPC0gZmluYW5jaWpza2lfcmFjdW5pICU+JSBtdXRhdGUoc2VrdG9yX21iID0gaWZlbHNlKHNla3Rvcl9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT3N0YWxlIEZJIixzZWt0b3JfbWIpKSAlPiUgZmlsdGVyKGRhdHVtPT16YWRuamlfZGF0dW0gJiB2cnN0YV9pem5vc2E9PSJCQUwgVCIgJiB2cnN0YV9pbW92aW5lPT0iVG90YWwiICYgcmF6aW5hPT0iTGlhYmlsaXRpZXMiICYgIXNla3RvciAlaW4lIGMoIlRPVEFMIiwiTkEiKSAmIHByb3R1c3RyYW5hX21iICVpbiUgYygiTWlyb3ZpbnNraSBmb25kb3ZpIiwiT3NpZ3VyYW5qYSIsIkludmVzdGljaWpza2kgZm9uZG92aSIsIk9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT3N0YWxlIEZJIikpICU+JSBncm91cF9ieShzZWt0b3JfbWIpICU+JSBzdW1tYXJpc2UoaXpsb3plbm9zdF9oYW5mYT1zdW0oaXpub3MsbmEucm0gPSBUKS8xMDAwMDAwMDAwKQ0KIyBza2xhcGFuamUgdSAxIHRpYmJsZQ0KYnJpZG92aSA8LSBsZWZ0X2pvaW4ocG9tMSxwb20yLGJ5PSJzZWt0b3JfbWIiKSAlPiUgbGVmdF9qb2luKHBvbTMsYnk9InByb3R1c3RyYW5hX21iIikgJT4lIGxlZnRfam9pbihwb200LGJ5PSJzZWt0b3JfbWIiKSAlPiUgbXV0YXRlKGl6bG96ZW5vc3RfdmVsaWNpbmFfc2VrdG9yPWl6bm9zL3ZlbGljaW5hX3Nla3RvcioxMDAgLCBpemxvemVub3N0X3ZlbGljaW5hX3Byb3R1c3RyYW5hPWl6bm9zL3ZlbGljaW5hX3Byb3R1c3RyYW5hKjEwMCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlKHNla3Rvcl9tYj1pZmVsc2Uoc2VrdG9yX21iPT0iUG9kdXplxIdhIiwiUE9EIixpZmVsc2Uoc2VrdG9yX21iPT0iT3N0YWxlIEZJIiwiT0ZJIixpZmVsc2Uoc2VrdG9yX21iPT0iQ2VudHJhbG5hIGJhbmthIiwiQ0IiLGlmZWxzZShzZWt0b3JfbWI9PSJLcmVkaXRuZSBpbnN0aXR1Y2lqZSIsIktJIixpZmVsc2Uoc2VrdG9yX21iPT0iSW52ZXN0aWNpanNraSBmb25kb3ZpIiwiSUYiLGlmZWxzZShzZWt0b3JfbWI9PSJPc2lndXJhbmphIiwiT1MiLGlmZWxzZShzZWt0b3JfbWI9PSJNaXJvdmluc2tpIGZvbmRvdmkiLCJNRiIsaWZlbHNlKHNla3Rvcl9tYj09IkRyxb5hdmEiLCJEUsW9IixpZmVsc2Uoc2VrdG9yX21iPT0iU3Rhbm92bmnFoXR2byIsIktVxIYiLGlmZWxzZShzZWt0b3JfbWI9PSJJbm96ZW1zdHZvIiwiSU5PIixpZmVsc2Uoc2VrdG9yX21iPT0iT3N0YWxpIGZpbmFuY2lqc2tpIHBvc3JlZG5pY2kiLCJPRlAiLCJOQSIpKSkpKSkpKSkpKSkgJT4lIG11dGF0ZShwcm90dXN0cmFuYV9tYj1pZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJQb2R1emXEh2EiLCJQT0QiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09Ik9zdGFsZSBGSSIsIk9GSSIsaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iQ2VudHJhbG5hIGJhbmthIiwiQ0IiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09IktyZWRpdG5lIGluc3RpdHVjaWplIiwiS0kiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09IkludmVzdGljaWpza2kgZm9uZG92aSIsIklGIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJPc2lndXJhbmphIiwiT1MiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09Ik1pcm92aW5za2kgZm9uZG92aSIsIk1GIixpZmVsc2UocHJvdHVzdHJhbmFfbWI9PSJEcsW+YXZhIiwiRFLFvSIsaWZlbHNlKHByb3R1c3RyYW5hX21iPT0iU3Rhbm92bmnFoXR2byIsIktVxIYiLGlmZWxzZShwcm90dXN0cmFuYV9tYj09Iklub3plbXN0dm8iLCJJTk8iLGlmZWxzZShwcm90dXN0cmFuYV9tYj09Ik9zdGFsaSBmaW5hbmNpanNraSBwb3NyZWRuaWNpIiwiT0ZQIiwiTkEiKSkpKSkpKSkpKSkpDQoNCiMgdXppbWFuamUgc2FtbyBicmlkb3ZhIGtvamkgc3UgdmXEh2kgb2QgNSUgaSBzYW1vIG9uaWggYnJpZG92YSBrb2ppIGltYWp1IHZlemUgc2EgSEFORkEtaW5pbSBzZWt0b3JpbWENCmJyaWRvdmkgPC0gYnJpZG92aSAlPiUgZmlsdGVyKGl6bG96ZW5vc3RfdmVsaWNpbmFfc2VrdG9yPjUgJiAoc2VrdG9yX21iICVpbiUgYygiTUYiLCJPUyIsIklGIiwiT0ZJIiwiT0ZQIikgfCBwcm90dXN0cmFuYV9tYiAlaW4lIGMoIk1GIiwiT1MiLCJJRiIsIk9GSSIsIk9GUCIpKSkNCiMgZGVmaW5pcmFuamUgdnJob3ZhIA0KdnJob3ZpIDwtIGxlZnRfam9pbihwb20yLHBvbTQsYnk9InNla3Rvcl9tYiIpICU+JSBtdXRhdGUoc2VrdG9yX21iPWlmZWxzZShzZWt0b3JfbWI9PSJQb2R1emXEh2EiLCJQT0QiLGlmZWxzZShzZWt0b3JfbWI9PSJPc3RhbGUgRkkiLCJPRkkiLGlmZWxzZShzZWt0b3JfbWI9PSJDZW50cmFsbmEgYmFua2EiLCJDQiIsaWZlbHNlKHNla3Rvcl9tYj09IktyZWRpdG5lIGluc3RpdHVjaWplIiwiS0kiLGlmZWxzZShzZWt0b3JfbWI9PSJJbnZlc3RpY2lqc2tpIGZvbmRvdmkiLCJJRiIsaWZlbHNlKHNla3Rvcl9tYj09Ik9zaWd1cmFuamEiLCJPUyIsaWZlbHNlKHNla3Rvcl9tYj09Ik1pcm92aW5za2kgZm9uZG92aSIsIk1GIixpZmVsc2Uoc2VrdG9yX21iPT0iRHLFvmF2YSIsIkRSxb0iLGlmZWxzZShzZWt0b3JfbWI9PSJTdGFub3ZuacWhdHZvIiwiS1XEhiIsaWZlbHNlKHNla3Rvcl9tYj09Iklub3plbXN0dm8iLCJJTk8iLGlmZWxzZShzZWt0b3JfbWI9PSJPc3RhbGkgZmluYW5jaWpza2kgcG9zcmVkbmljaSIsIk9GUCIsIk5BIikpKSkpKSkpKSkpKSAlPiUgbXV0YXRlKGhhbmZhPWlmZWxzZShzZWt0b3JfbWIgJWluJSBjKCJJRiIsIk1GIiwiT1MiLCJPRkkiLCJPRlAiKSwiZGEiLCJuZSIpKSAlPiUgbXV0YXRlKHZlbGljaW5hX2tydWdhPWlmZWxzZShoYW5mYT09ImRhIix2ZWxpY2luYV9zZWt0b3IsaXpsb3plbm9zdF9oYW5mYSkpICU+JSBmaWx0ZXIoc2VrdG9yX21iIT0iQ0IiKQ0KDQojIGtyZWlyYW5qZSBtcmXFvm5vZyBvYmpla3RhDQpncmFmIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gYnJpZG92aSwgdmVydGljZXMgPSB2cmhvdmksIGRpcmVjdGVkID0gVCkNCiMgcG9zdGF2bGphbmplIGJvamUgdnJoYSAoYWtvIEhhbmZhIG5hZHppcmUgImJsdWUiLCBpbmHEjWUgImdyYXkiKQ0KVihncmFmKSRjb2xvciA8LSBpZmVsc2UoVihncmFmKSRoYW5mYSA9PSAiZGEiLCAiZGVlcHNreWJsdWUzIiwgImF6dXJlMyIpDQojIHZlbGnEjWluYSBvem5ha2EgbmEgdnJob3ZpbWENClYoZ3JhZikkbGFiZWwuY2V4ID0gMC44DQojIHBvc3RhdmxqYW5qZSBib2plIGJyaWRhIChha28gPDUlIGltb3ZpbmUsIG9uZGEgbmVtYSBicmlkYSwgYWtvIGRvIDEwJSBvbmRhIHplbGVubywgYWtvIGRvIDIwJSBvbmRhIG5hcmFuxI1hc3RvLCBhIHByZWtvIGNydmVubykNCkUoZ3JhZikkY29sb3IgPC0gaWZlbHNlKEUoZ3JhZikkaXpsb3plbm9zdF92ZWxpY2luYV9zZWt0b3IgPD0gMTAsICJkYXJrZ3JlZW4iLCBpZmVsc2UoRShncmFmKSRpemxvemVub3N0X3ZlbGljaW5hX3Nla3RvciA8PSAxNSwieWVsbG93MyIsaWZlbHNlKEUoZ3JhZikkaXpsb3plbm9zdF92ZWxpY2luYV9zZWt0b3I8PTIwLCJkYXJrb3JhbmdlIiwiZGFya3JlZCIpKSkNCg0KIyBzbGlrYSBtcmXFvmUgcG92ZXphbm9zdGkNCg0KIyByYXpuZSBkZWJsamluZSBicmlkb3ZhDQojcGxvdChncmFmLCB2ZXJ0ZXguc2l6ZSA9IFYoZ3JhZikkdmVsaWNpbmFfa3J1Z2EvMiwgZWRnZS5hcnJvdy5zaXplID0gMC41LCBsYXlvdXQ9bGF5b3V0X25pY2VseShncmFmKSwgZWRnZS53aWR0aCA9IEUoZ3JhZikkaXpsb3plbm9zdF92ZWxpY2luYV9zZWt0b3IvOCwgdmVydGV4LmxhYmVsLmNvbG9yID0gImJsYWNrIiwgdmVydGV4LmZyYW1lLmNvbG9yPU5BKQ0KIyBqZWRuYWtlIGRlYmxqaW5lIGJyaWRvdmENCnBsb3QoZ3JhZiwgdmVydGV4LnNpemUgPSAyNSwgZWRnZS5hcnJvdy5zaXplID0gMC41LCBsYXlvdXQ9bGF5b3V0X25pY2VseShncmFmKSwgZWRnZS53aWR0aCA9IDIsIHZlcnRleC5sYWJlbC5jb2xvciA9ICJibGFjayIsIHZlcnRleC5mcmFtZS5jb2xvcj1OQSkNCiMgbGVnZW5kYQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPWMoIjw1IiwiPDU7MTBdIiwiPDEwOzE1XSIsIjwxNTsyMF0iLCI+MjAiKSwgZmlsbD1jKCJ3aGl0ZSIsICJkYXJrZ3JlZW4iLCJ5ZWxsb3czIiwiZGFya29yYW5nZSIsImRhcmtyZWQiKSwgdGl0bGUgPSAiT3puYWtlIGJvamEgc3RyZWxpY2EgXG4gKHUgJSB1a3VwbmUgaW1vdmluZSBzZWt0b3JhKSIsIGNleD0wLjgsIGJ0eT0ibiIpDQojIGJyaXNhbmplIHByaXZyZW1lbmloIHRhYmxpY2ENCnJtKHphZG5qaV9kYXR1bSxicl9kYW5hLHBvbTEscG9tMixwb20zLHBvbTQscG9tLGJyaWRvdmksdnJob3ZpLGdyYWYpDQoNCmBgYA0KDQojIyMgNi4zLiBTaGlueSBhcGxpa2FjaWphDQoNCkthZGEgc3UgcG9kYWNpIHUgdGlkeSBmb3JtYXR1LCBvbmRhIGplIG1vZ3XEh2UgbmFwcmF2aXRpIHNsamVkZcSHdSBhcGxpa2FjaWp1IHphIGFuYWxpenUga3JldGFuamEgdSBzdXN0YXZ1Lg0KDQohW10oc2hpbnlfYmlsYW5jYV9zbGlrYS5QTkcpDQoNCiMjIDcuIEFuYWxpemEgaSBrb211bmlrYWNpamEgcmV6dWx0YXRhDQoNCiMjIyA3LjEuIFBsb3RseQ0KDQpPdm8gamUgcHJpbWplciBHYW50dC1ncmFmaWtvbmEga29qaSBzdGUgdmlkamVsaSBwcm/FoWxpIHRqZWRhbiBzYSB2cmVtZW5za2ltIHBsYW5vbSBha3Rpdm5vc3RpIG9rbyBwcmlwcmVtZSA0LiBicm9qYSBNYWtyb3BydWRlbmNpamFsbm9nIHNrZW5lcmEgcml6aWthLg0KDQohW10oR2FudF9za2VuZXIuUE5HKQ0KDQojIyMgNy4yLiBHYXBtaW5kZXIgcHJpbWplcg0KDQpIYW5zIFJvc2xpbmcgamUgamVkbm8gb2QgbmFqcG96bmF0aWppaCBpbWVuYSB1IHN0YXRpc3RpxI1raW0ga3J1Z292aW1hIGkgdmVsaWtpIHBvcHVsYXJpemF0b3IgImRhdGEgc2NpZW5jZWEiLCBuamVnb3YgW1RFRCB0YWxrXShodHRwczovL3d3dy50ZWQuY29tL3RhbGtzL2hhbnNfcm9zbGluZ190aGVfYmVzdF9zdGF0c195b3VfdmVfZXZlcl9zZWVuP2xhbmd1YWdlPWhyKSBqZSBqZWRhbiBvZCBuYWpnbGVkYW5pamloIGlrYWRhICh2ZWxpa2EgcHJlcG9ydWthIGRhIGdhIHBvZ2xlZGF0ZSkuDQoNCiFbXShHYXBtaW5kZXIuUE5HKQ0KDQojIyMgNy4zLiBTaGlueSBtcmXFvmUgT2VOQi1hDQoNClZpZGkgZm9sZGVyIEpWSV9Db250YWdpb24uDQoNCiFbXShDb250YWdpb24uUE5HKQ0KDQojIyMgNy40LiBNYXBhIEVVDQoNClZybG8gamVkbm9zdGF2bm8gc2UgbW/FvmUgbmFwcmF2aXRpIGkgbWFwYSBFVSBwbyB6ZW1samFtYS4gTnByLCBwcmlrYXogZGVmaW5pY2lqZSByZWdpamEga29qZSBwcmlrYXp1amVtbyB1IHNrZW5lcnUuDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdyaWQpDQpsaWJyYXJ5KHJ3b3JsZG1hcCkNCmxpYnJhcnkoZXVyb3N0YXQpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCg0KIyBHZXQgdGhlIHdvcmxkIG1hcA0Kd29ybGRNYXAgPC0gZ2V0TWFwKCkNCg0KIyBNZW1iZXIgU3RhdGVzIG9mIHRoZSBFdXJvcGVhbiBVbmlvbg0KcmVnID0gZGF0YS5mcmFtZShyZWZfYXJlYT1jKCJBVCIsIkJFIiwiQkciLCJIUiIsIkNZIiwiQ1oiLCJESyIsIkVFIiwiRkkiLCJGUiIsIkRFIiwiR1IiLCJIVSIsIklFIiwiSVQiLCJMViIsIkxUIiwiTFUiLCJNVCIsIk5MIiwiUEwiLCJQVCIsIlJPIiwiU0siLCJTSSIsIkVTIiwiU0UiLCJHQiIpLGNvdW50cnk9YygiQXVzdHJpYSIsIkJlbGdpdW0iLCJCdWxnYXJpYSIsIkNyb2F0aWEiLCJDeXBydXMiLCJDemVjaCBSZXAuIiwiRGVubWFyayIsIkVzdG9uaWEiLCJGaW5sYW5kIiwiRnJhbmNlIiwiR2VybWFueSIsIkdyZWVjZSIsIkh1bmdhcnkiLCJJcmVsYW5kIiwiSXRhbHkiLCJMYXR2aWEiLCJMaXRodWFuaWEiLCJMdXhlbWJvdXJnIiwiTWFsdGEiLCJOZXRoZXJsYW5kcyIsIlBvbGFuZCIsIlBvcnR1Z2FsIiwiUm9tYW5pYSIsIlNsb3Zha2lhIiwiU2xvdmVuaWEiLCJTcGFpbiIsIlN3ZWRlbiIsIlVuaXRlZCBLaW5nZG9tIikscmVnaWphPWMoIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJIUiIsIk90aGVyIEVVIiwiQ0VFIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJDRUUiLCJPdGhlciBFVSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJDRUUiLCJPdGhlciBFVSIsIkNFRSIsIkNFRSIsIkNFRSIsIk90aGVyIEVVIiwiT3RoZXIgRVUiLCJPdGhlciBFVSIpKQ0KDQojIFNlbGVjdCBvbmx5IHRoZSBpbmRleCBvZiBzdGF0ZXMgbWVtYmVyIG9mIHRoZSBFLlUuDQppbmRFVSA8LSB3aGljaCh3b3JsZE1hcCROQU1FICVpbiUgcmVnJGNvdW50cnkpDQoNCiMgRXh0cmFjdCBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIGJvcmRlcidzIGNvb3JkaW5hdGVzIG9mIG1lbWJlcnMgc3RhdGVzIG9mIEUuVS4gDQpldXJvcGVDb29yZHMgPC0gbGFwcGx5KGluZEVVLCBmdW5jdGlvbihpKXsNCiAgZGYgPC0gZGF0YS5mcmFtZSh3b3JsZE1hcEBwb2x5Z29uc1tbaV1dQFBvbHlnb25zW1sxXV1AY29vcmRzKQ0KICBkZiRyZWdpb24gPWFzLmNoYXJhY3Rlcih3b3JsZE1hcCROQU1FW2ldKQ0KICBjb2xuYW1lcyhkZikgPC0gbGlzdCgibG9uZyIsICJsYXQiLCAicmVnaW9uIikNCiAgcmV0dXJuKGRmKQ0KfSkNCg0KZXVyb3BlQ29vcmRzIDwtIGRvLmNhbGwoInJiaW5kIiwgZXVyb3BlQ29vcmRzKQ0KDQojIDEuIE1hcGEgcmVnaWphICMjIyMNCmV1cm9wZWFuVW5pb25UYWJsZSA8LSBkYXRhLmZyYW1lKGNvdW50cnkgPSByZWckY291bnRyeSwgdmFsdWUgPSByZWckcmVnaWphKQ0KZXVyb3BlQ29vcmRzJHZhbHVlIDwtIGV1cm9wZWFuVW5pb25UYWJsZSR2YWx1ZVttYXRjaChldXJvcGVDb29yZHMkcmVnaW9uLGV1cm9wZWFuVW5pb25UYWJsZSRjb3VudHJ5KV0NCg0KIyBQbG90IHRoZSBtYXANClAgPC0gZ2dwbG90KCkgKyBnZW9tX3BvbHlnb24oZGF0YSA9IGV1cm9wZUNvb3JkcywgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IHJlZ2lvbiwgZmlsbCA9IHZhbHVlKSwgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDAuMSkgKyBjb29yZF9tYXAoeGxpbSA9IGMoLTEzLCAzNSksICB5bGltID0gYygzMiwgNzEpKQ0KUCA8LSBQICsgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gIlJlZ2lqYSIsIG5hLnZhbHVlID0gImdyZXk1MCIpDQpQIDwtIFAgKyB0aGVtZSgjcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gTkEpLA0KICAjcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIGNvbG91ciA9IE5BKSwNCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgI3JlY3QgPSBlbGVtZW50X2JsYW5rKCksDQogIHBsb3QubWFyZ2luID0gdW5pdCgwICogYygtMS41LCAtMS41LCAtMS41LCAtMS41KSwgImxpbmVzIikpDQpQDQoNClAgPC0gUCArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobmFtZSA9ICJHcm93dGggUmF0ZSIsIGxvdyA9ICIjRkYwMDAwRkYiLCBoaWdoID0gIiNGRkZGMDBGRiIsIG5hLnZhbHVlID0gImdyZXk1MCIpDQoNCg0KYGBgDQoNCg0KDQoNCkplZG5ha28gamVkbm9zdGF2bm8gc2UgbW/FvmUgbmFwcmF2aXRpIGkga29udGludWlyYW5hIG1hcGEga29qYSBucHIuIHByaWthenVqZSBrdW11bGF0aXZuaSByYXN0IEJEUC1hIG9kIDIwMTAuIHBvIEVVIHplbWxqYW1hLg0KDQpgYGB7cn0NCnBvbSA8LSBnZXRfZXVyb3N0YXQoaWQ9Im5hbXFfMTBfZ2RwIikgJT4lIGZpbHRlcihuYV9pdGVtPT0iQjFHUSIgJiBzX2Fkaj09Ik5TQSIgJiB1bml0PT0iQ0xWMTBfTU5BQyIpICU+JSBzZWxlY3QodGltZSxnZW8sYmRwPXZhbHVlcykgJT4lIGFycmFuZ2UodGltZSkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZ3JvdXBfYnkoZ2VvKSAlPiUgbXV0YXRlKGJkcF95ID0gKGJkcCArIGxhZyhiZHAsMSkrIGxhZyhiZHAsMikgKyBsYWcoYmRwLDMpKSkgJT4lIGZpbHRlcih0aW1lPj0iMjAwNy0xMC0wMSIpICU+JSBtdXRhdGUoZGF0dW0gPSBtYWtlX2RhdGUoaWZlbHNlKG1vbnRoKHRpbWUpPj0xMCx5ZWFyKHRpbWUpKzEseWVhcih0aW1lKSksaWZlbHNlKG1vbnRoKHRpbWUpPj0xMCwxLG1vbnRoKHRpbWUpKzMpLDEpIC0gMSkgJT4lIHNlbGVjdChkYXR1bSxyZWZfYXJlYT1nZW8sYmRwX3kpICU+JSBuYS5vbWl0KCkgJT4lIHVuZ3JvdXAoKQ0KYmF6YSA8LSBwb20gJT4lIGZpbHRlcihkYXR1bT09IjIwMTAtMTItMzEiKSAlPiUgc2VsZWN0KHJlZl9hcmVhLGJhemE9YmRwX3kpDQpkZWx0YV9iZHAgPC0gbGVmdF9qb2luKHBvbSxiYXphLGJ5PWMoInJlZl9hcmVhIikpICU+JSBtdXRhdGUoaW5kZWtzPWJkcF95L2JhemEqMTAwKSAlPiUgZmlsdGVyKGRhdHVtPT0iMjAxOS0wOS0zMCIpICU+JSBsZWZ0X2pvaW4ocmVnLGJ5PSJyZWZfYXJlYSIpICU+JSBuYS5vbWl0KCkNCg0KZXVyb3BlYW5VbmlvblRhYmxlIDwtIGRhdGEuZnJhbWUoY291bnRyeSA9IGRlbHRhX2JkcCRjb3VudHJ5LCB2YWx1ZSA9IGRlbHRhX2JkcCRpbmRla3MpDQpldXJvcGVDb29yZHMkdmFsdWUgPC0gZXVyb3BlYW5VbmlvblRhYmxlJHZhbHVlW21hdGNoKGV1cm9wZUNvb3JkcyRyZWdpb24sZXVyb3BlYW5VbmlvblRhYmxlJGNvdW50cnkpXQ0KDQojIFBsb3QgdGhlIG1hcA0KUCA8LSBnZ3Bsb3QoKSArIGdlb21fcG9seWdvbihkYXRhID0gZXVyb3BlQ29vcmRzLCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gcmVnaW9uLCBmaWxsID0gdmFsdWUpLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC4xKSArIGNvb3JkX21hcCh4bGltID0gYygtMTMsIDM1KSwgIHlsaW0gPSBjKDMyLCA3MSkpDQpQIDwtIFAgKyBzY2FsZV9maWxsX2dyYWRpZW50KG5hbWUgPSAiS3VtdWxhdGl2bmkgcmFzdCBCRFAtYSBvZCAyMDEwLiIsIGxvdyA9ICJyZWQiLCBoaWdoID0gImdyZWVuIiwgbmEudmFsdWUgPSAiZ3JleTUwIikNClAgPC0gUCArIHRoZW1lKCNwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9IE5BKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksDQogICNwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgY29sb3VyID0gTkEpLA0KICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAjcmVjdCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgcGxvdC5tYXJnaW4gPSB1bml0KDAgKiBjKC0xLjUsIC0xLjUsIC0xLjUsIC0xLjUpLCAibGluZXMiKSkNClANCiMgYnJpc2FuamUgcHJpdnJlbWVuaWggdGFibGljYQ0Kcm0od29ybGRNYXAscmVnLGluZEVVLGV1cm9wZUNvb3JkcyxldXJvcGVhblVuaW9uVGFibGUsUCxwb20sYmF6YSxkZWx0YV9iZHApDQoNCmBgYA0KDQojIyMgNy41LiBXb3JkIGNsb3VkIHJpamXEjWkga29qZSBzdSBzZSBuYWrEjWXFocSHZSBrb3Jpc3RpbGUgdSAzLiBicm9qdSBza2VuZXJhDQoNCiFbXSh3b3JkX2Nsb3VkLnBuZykNCg0K